this.setState((state, props) => ({
counter: state.counter + props.increment
}));
<p dangerouslySetInnerHTML={
{
__html:"nmad"}}></p>
component.defaultProps = {
}
或者内部
static defaultProps = {
name: 'stranger'
}
Toolbar.propTypes = {
changeTheme: PropTypes.func
};
11.template
空标签或者
其中mount和update之前都会执行render
if (isLoggedIn) {
button = <LogoutButton onClick={
this.handleLogoutClick} />;
} else {
button = <LoginButton onClick={
this.handleLoginClick} />;
}
return (
<div>
<Greeting isLoggedIn={
isLoggedIn} />
{
button}
</div>
);
使用&&或者三目运算符或者内部返回false
注意,内部返回false组件生命周期仍然
{
unreadMessages.length > 0 &&
<h2>
You have {
unreadMessages.length} unread messages.
</h2>
}
{
this.state.showWarning ?
<WarningBanner warn={
this.state.showWarning} />:
''
}
function WarningBanner(props) {
if (!props.warn) {
return null;
}
return (
<div className="warning">
Warning!
</div>
);
}
const ThemeContext = React.createContext('light');
// 设置react-devtools中context的名字
ThemeContext.displayName = 'MyDisplayName';
这个是非必须的,但是组件会使用优先近的provider,没有就使用默认值
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
3.1 直接注册获取
static contextType = ThemeContext;
或者
ThemedButton.contextType = ThemeContext
这样都可以在this拿到context
render() {
return <Button theme={
this.context} />;
}
3.2 不注册获取
<ThemeContext.Consumer>
{
value => value}
</ThemeContext.Consumer>
或使用hook获取
function Example() {
const locale = useContext(LocaleContext);
const theme = useContext(ThemeContext);
// ...
}
//已弃用的方法
与vue一样,dom上用ref注册,然后用this.refs.xx来引用
//第二种方法,在state上添加
<section ref="(dom) => this.state.dom = dom">
//现在的方法,在构造函数中先声明注册名,然后在模板中注册
//注意ref正常情况下传给function组件无效
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return <div ref={
this.myRef} />;
}
}
const node = this.myRef.current;
//注意myRef可以传递而不直接使用,因此也可以操作孙子节点行为,这是第三种方法优越之处
// 第四种方法,使用ref回调函数,传入的时候自动会把当前dom作为第一个参数进行执行
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
this.textInput = null;
this.setTextInputRef = element => {
console.log(element)
this.textInput = element;
};
this.focusTextInput = () => {
// 使用原生 DOM API 使 text 输入框获得焦点
if (this.textInput) this.textInput.focus();
};
}
componentDidMount() {
// 组件挂载后,让文本框自动获得焦点
this.focusTextInput();
}
render() {
// 使用 `ref` 的回调函数将 text 输入框 DOM 节点的引用存储到 React
// 实例上(比如 this.textInput)
return (
<div>
<input
type="text"
ref={
this.setTextInputRef}
/>
<input
type="button"
value="Focus the text input"
onClick={
this.focusTextInput}
/>
</div>
);
}
}
//这是函数组件专用写法
//这是把自身的ref转发到了子组件button上
//注意可以设置函数名或者其displayName修改tools中显示的名字
const MyFunctionComponent = React.forwardRef((props, ref) => {
return <LogProps {
...props} ref={
ref} />;
});
//当然也可以中间组件不要用ref接受组件引用,用props进行传递
//我觉得直接用props更直观更好,不要搞什么花里胡哨的组件转发
// 最常见的HOC传递方法,先用React.forwardRef转发,然后转发的时候ref变成props,然后装饰组件将props转给子组件
function logProps(Component) {
class LogProps extends React.Component {
componentDidUpdate(prevProps) {
console.log('old props:', prevProps);
console.log('new props:', this.props);
}
render() {
const {
forwardedRef, ...rest} = this.props;
// 将自定义的 prop 属性 “forwardedRef” 定义为 ref
return <Component ref={
forwardedRef} {
...rest} />;
}
}
// 注意 React.forwardRef 回调的第二个参数 “ref”。
// 我们可以将其作为常规 prop 属性传递给 LogProps,例如 “forwardedRef”
// 然后它就可以被挂载到被 LogProps 包裹的子组件上。
return React.forwardRef((props, ref) => {
return <LogProps {
...props} forwardedRef={
ref} />;
});
}
使用pubsub
// 发起者
Pubsub.publish("evt",this.state.name)
//接受者
Pubsub.subscribe("evt",(msg, data) => {
console.log(msg);//evt
console.log(data);//this.state.name即son11
})
json-server
json-server 文件名.json --port 4000
如下,第二个路由无论当前hash是啥都能匹配到
<Route path="/home" component={
Son}></Route>
<Route path="/" component={
Son}></Route>
为了解决这个问题,添加属性exact解决
<Route path="/home" component={
Son}></Route>
<Route path="/" component={
Son} exact></Route>
如果一组路由中只想匹配一个外部可以加
如果有重定向的需求:
<Redirect from="/" to="/home" exact></Redirect>
关于二级路由吧二级组件写在一级组件中,注意二级路由的url要写全
如果要监控路由变化
history.listen((link) => {
//link是当前的新location
})
如果要手动跳转路由
props.history.push('/home')
如果要路由传参
//params方法
// 1.先设置参数
<Route path="/home/:id" component={
Son}></Route>
// 2.发送参数
<Link to="/home/99">点我起飞</Link>
// 3.接收参数
console.log(props.match.props.params.id)
// 但是上述方法的缺点在于只能传字符串
//query方法
// 1.发送参数
<Link to={
pathname: "/home", query: {
name: 'zl' } }>点我起飞</Link>
// 2.接收参数
console.log(props.location.query.name)
就是将组件作为参数,返回也是一个组件
比如
export default withRouter(home);
将location、match、history添加到props上,即使该组件不是一个route
给函数组件使用状态特性用的
useState()返回一个数组
arr[0]是那个状态,arr[1]是修改状态的函数(类似setState)
如果定义多个状态
let arr = userState({
val1: 0,
val2: 1,
val3: 2,
})
// 使用状态
console.log(arr[0].val1)
// 修改状态(没错,这里只能全体修改)
arr[1]({
val1: 2,
val2: 3,
val3: 4,
})
// 当然也可以多次声明,将不同状态独立
// 这样的话注意useState和副作用的顺序
hook的生命周期也被简化,useEffect表示componentDidMount、componentDidUpdate 和 componentWillUnmoun
function Example() {
const [count, setCount] = useState(0);
// 相当于 componentDidMount 和 componentDidUpdate:
useEffect(() => {
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
// 这里的返回值函数会在componentWillUnmoun触发
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
return (
<div>
...
</div>
);
}
关于自定义hook,感觉上是用来提取重复的判断逻辑
用scu只在某些数据更新时才重新渲染,减少不必要的渲染
class CounterButton extends React.Component {
constructor(props) {
...
}
shouldComponentUpdate(nextProps, nextState) {
if (this.props.color !== nextProps.color) {
return true;
}
if (this.state.count !== nextState.count) {
return true;
}
return false;
}
render() {
return (
...
);
}
}
或者使用浅比较,当然浅比较如果发现属性变化前后的引用一样,那么他不会触发渲染
class CounterButton extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
count: 1};
}
render() {
return (
<button
color={
this.props.color}
onClick={
() => this.setState(state => ({
count: state.count + 1}))}>
Count: {
this.state.count}
</button>
);
}
}
这是一种将元素渲染到任意dom的方法,但是注意react树的关系没有变化
因此点击事件等仍然可以按react树的形式冒泡
render() {
// React 并*没有*创建一个新的 div。它只是把子元素渲染到 `domNode` 中。
// `domNode` 是一个可以在任何位置的有效 DOM 节点。
return ReactDOM.createPortal(
this.props.children,
domNode
);
}
//设置监听,触发页面修改
componentDidMount() {
store.subscribe(() => {
this.setState({
num: store.getState()
})
})
}
react-redux不再使用subscribe,而是用provider组件中注入store,
connect( mapStateToProps, mapDispatchToProps)(component)来封装store的输入输出规则
在7.1版本后也可以用useSelector和useDispatch来使用代替connect
他们都是副作用(类似hook或者生命周期这样),但是useMemo和useEffect的执行时机不同。useEffect会在dom更新完之后执行,而useMemo会在dom渲染时就执行,所以不要在useMemo中书写触发渲染的操作.
应用场景:
1.useMemo+memo可以实现父组件重渲染,子组件不重新渲染
2.useMemo化的函数如果在模版中立即执行,那么useMemo未监听的变量变化时该函数也不会再执行一次。
useCallback(fn, deps) 相当于 useMemo(() => fn, deps)
render prop 是一个用于告知组件需要渲染什么内容的函数 prop
直接作用:dispatch中可以接受一个以dispatch本身作为第一个参数的函数了
间接作用:现在异步操作可以放在action里了(因为action是个函数),更加解耦合
可以和redux-thunk互相替代