创建react项目
在终端输入npx create-react-app xxx
创建一个react项目,通过npm start
启动该项目.
index.js
StrickMode
是一个严格模式,它可以严格的进行功能审查
组件方式
- 函数式组件
- JSX语法,将html+js融合的很深,他每个组件只能返回一个根元素.每个组件都需要正确的闭合
- 插值功能,通过
{}
来实现js的内容插入到html中.同样的html的标签可以直接作为值存储在js的类中.而不用在加上字符串符号.
- 因为每次都只能返回一个根元素,通常的做法是用
<></>
来进行闭合.当然有些元素需要传入key或者其他属性,这时候就可以使用react提供的Fragment
来进行闭合
- 样式设置.他使用的是
className
来代替原来的class
- 类组件
组件通信
通过props和解构的方式来实现组件间的通信
传值
他可以单个数据单个数据的传输,也可以直接传进来一个对象,然后再获取对象中的值,都是没问题的
传递组件
而且父组件也可以向子组件传递另一个组件,只要把这个组件放在对应的html中,他就可以正确的展示出来
子组件传递给父组件
这里简单讲就是
- 状态提升,将该组件的属性提升到父组件中,然后通过传参的方式让子组件引用父组件的属性
- 自定义事件下传,再将修改这个属性的方法封装后传递给子组件,让子组件调用这个方法进行修改.
React的常用Hook
useState
最基础的状态管理
1 2
| const [enabled, setEnabled] = useState(false);
|
enabled是状态值,而setEnabled是一个方法,他可以设置你的状态值
useReducer
他使用MVI的开发思路,将意图和状态分开,可以在https://zfxt.top/posts/c7f557a/?highlight=mvi查看关于MVI的相关属性.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| import {useReducer} from 'react';
interface State { count: number };
type CounterAction = | { type: "reset" } | { type: "setCount"; value: State["count"] }
const initialState: State = { count: 0 };
function stateReducer(state: State, action: CounterAction): State { switch (action.type) { case "reset": return initialState; case "setCount": return { ...state, count: action.value }; default: throw new Error("Unknown action"); } }
export default function App() { const [state, dispatch] = useReducer(stateReducer, initialState);
const addFive = () => dispatch({ type: "setCount", value: state.count + 5 }); const reset = () => dispatch({ type: "reset" });
return ( <div> <h1>欢迎来到我的计数器</h1>
<p>计数: {state.count}</p> <button onClick={addFive}>加 5</button> <button onClick={reset}>重置</button> </div> ); }
|
这个钩子需要接受两个参数,第一个是接受到意图时,进入某个方法,判断意图并操作,第二个参数是初始状态.
然后使用这个dispatch方法时,需要传递对应的参数来判断需要进行什么操作.
useContext
这就是个全局隐式传递方法的函数,
我们一般传递属性都是通过props,显然的传递我们需要传递的对象,这样往往需要很多的操作,规定父子组件如何传递如何接受,
而使用useContext就可以进行隐式的接受,他是直接在ui树上进行传递的,也就是所有的子组件都可以获取.(包括递归的子组件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| import { createContext, useContext } from 'react';
const ThemeContext = createContext(null);
export default function MyApp() { return ( <ThemeContext.Provider value="dark"> <Form /> </ThemeContext.Provider> ) }
function Form() { return ( <Panel title="Welcome"> <Button>Sign up</Button> <Button>Log in</Button> </Panel> ); }
function Panel({ title, children }) { const theme = useContext(ThemeContext); const className = 'panel-' + theme; return ( <section className={className}> <h1>{title}</h1> {children} </section> ) }
function Button({ children }) { const theme = useContext(ThemeContext); const className = 'button-' + theme; return ( <button className={className}> {children} </button> ); }
|
他的步骤就是create,再provider,然后使用useContext获取.
useMemo
进行数据缓存的钩子,用来跳过代价昂贵的重新计算
1 2 3 4 5 6
| import { useMemo } from 'react';
function TodoList({ todos, tab, theme }) { const visibleTodos = useMemo(() => filterTodos(todos, tab), [todos, tab]); }
|
设置只有在某些数据变化时,他才会重新渲染,避免因为其他组建的渲染导致的重新计算
useCollback
与useMemo类似,但是他是缓存函数而不是数据
useRef
- 记录状态
他会记住你当前这个值的状态,并且他不会随着你对该元素的修改而重新渲染页面,也就是不会你的更新不会立刻展示在页面中.
- 获取dom
他的获取方式是.current
来获取,他还可以直接获取dom元素的引用,或者其他的子组件,这样他可以直接调用这个原生dom的方法(例如获取input框,然后使用其对焦功能)或者子组件的方法(这样子要求,他才能调用子组件的方法.)
useEffect
副作用函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function MyComponent() { useEffect(() => { });
useEffect(() => { }, []);
useEffect(() => { }, [a, b]); return <div />; }
|
他的第二个参数,如果是空他就每次渲染都执行.就是监控值,每次修改这个监控值,都会导致他的Effect的调用,
memo方法
如果这个组件的props没有发生变化,他就不会进行重新渲染
他通常与useCallback
一起使用,这样子才能实现props的不发生变化(如果不缓存方法的话,他传递的props每次都会变更为一个新方法)