- 安装官⽅方脚⼿手架:
npx create-react-app my-react-app - 进入:
cd my-react-app - 启动项目
npm start - 暴露配置项
npm run eject
如果出现错误类似/babel-preset-reactapp/node_modules/@babel/runtime/helpers/slicedToArray' at webpackMissingModule ‘,就npm add @babel/runtime
setState
-
setState是批量量执行的,因此对同一个状态执行多次只起一次作用,多个状态更新可以放在同一个setState中进⾏
-
setState通常是异步的,因此如果要获取到最新状态值有以下三种⽅方式:
//传递函数给setState⽅方法
this.setState((nextState, props) => ({counter: state.counter + 1}));//
//使用定时器
setTimeout(() => {
this.changeValue();
}, 0);
//原⽣生事件中修改状态
componentDidMount(){
document.body.addEventListener('click',this.changeValue, false)
}
changeValue = () => {
this.setState({counter:this.state.counter+1})
console.log(this.state.counter)
}
为什什么 setState只有在React合成事件和⽣生命周期数中是异步的,在原⽣生事件和setTimeout、setInterval、addEventListener中都是同步的?
原⽣生事件绑定不会通过合成事件的⽅式处理,自然也不会进入更新事务的处理流程。setTimeout也一样,在setTimeout回调执行时已经完成了原更新组件流程,也不会再进入异步更新流程,其结果自然就是同步的了。
组件通信
- 子传父
// index.js
ReactDOM.render(<App title="首页" />,
document.querySelector('#root'));
// App.js
<h2>{this.props.title}</h2>
- 父传子(状态提升)
// StateMgt
<Clock change={this.onChange}/>
// Clock
this.timerID = setInterval(() => {
this.setState({
date: new Date()
}, ()=>{
// 每次状态更新就通知父组件
this.props.change(this.state.date);
});
}, 1000);
- 跨层级组件之间通信 context
//AppContext.js
import React, { Component } from 'react'
export const Context = React.createContext()
export const Provider = Context.Provider
export const Consumer = Context.Consumer
//App.js
import { Provider } from './AppContext'
const store = {
home:{},
user:{}
}
function App() {
return (
<div className="app">
<Provider value={store}>
<Home />
</Provider>
</div>
);
}
//Home.js
import { Consumer } from '../AppContext';
function Home(){
return (<Consumer>{ctx => <HomeCmp {...ctx} />}</Consumer>)
}
//HomeCmp.js
function HomeCmp(props) {
const { home, user } = props
return (...)
}
高阶组件
function Child(props) {
return <div>Child</div>
}
const foo = Cmp => props => {
return <Cmp {...props} />
}
//使用
const Foo = foo(Child)
<Foo />
//链式调用
const Food = foo(foo(Child))
<Food />
- consumer结合高阶组件
const handleConsumer = Cmp => props => {
return <Consumer>{ctx => <Cmp {...ctx} {...props}></Cmp>}</Consumer>
}
//使用
const HandleConsumer = handleConsumer(UserCmp)
<HandleConsumer />
装饰器
1.npm run eject
2.配置package.json
"babel": {
"presets": [ "react-app" ],
"plugins": [
[
"@babel/plugin-proposal-decorators",
{"legacy": true}
]
]
}
3.安装装饰器器插件 npm install @babel/plugin-proposal-decorators -- save-dev
4.使用在class组件上
const foo = Cmp => props => {
return (
<div className="border">
<Cmp />
</div>
);
};
@foo
@foo
class xxx ...
useContext
import React, { useContext } from "react";
import { Context } from "../AppContext";
export default function UseContextPage() {
const ctx = useContext(Context);
const { name } = ctx.user;
return (
<div>
<h1>UseContextPage</h1>
<p>{name}</p>
</div>
);
}
useReducer
function fruitReducer(state = [], action) {
switch (action.type) {
case "replace":
case "init":
return [...action.payload];
case "add":
return [...state, action.payload];
default:
return state;
}
}
export default function UseReducerPage() {
const [fruits, dispatch] = useReducer(fruitReducer,[]);
useEffect(() => {
setTimeout(() => {
dispatch({ type: "init", payload: ["apple","banana"] });
}, 1000);
return () => {};
}, []);
return (
<div>
<h1>UseReducerPage</h1>
<FruitAdd fruits={fruits} addFruit={name => dispatch({ type: "add", payload: name })}/>
<FruitList fruits={fruits} setFruits={newList => dispatch({ type: "init",payload: newList })}/>
</div>
);
}