react萌新的读书小笔记(二)

useReducer

import React, {useReducer} from 'react'

function reducer(state, action) {
    switch (action.type) {
        case 'changeName':
            return {...state, name: action.value}
        case 'changeAge':
            return {...state, age: action.value}
        case 'changeSex':
            state.sex+=1;
            return {...state }
        default:
            throw Error('报错啦')
    }
}

export default function App() {
    const [{name, age}, dispatch] = useReducer(reducer, {name:'',age:''});
    return <div>
        <input type="text"
               value={name}
               onChange={e => dispatch({type: 'changeName', value: e.target.value})}
        />
        <p>{name}</p>
        <input type="text"
               value={age}
               onChange={e => dispatch({type: 'changeAge', value: e.target.value})}
        />
        <p>{age}</p>
		<button onClick={()=>dispatch({type:'changeSex'})}>+</button>
        {sex}
    </div>

}

onChange 监听
onBlur  失去焦点

useState

复杂类型的操作

export default function App() {
    let [num, setNum] = useState([]);
    const add1 = () => {
        setNum([...num, {
            value: num.length
        }])
    }
    const add2 = () => {
        setNum([...num.reverse()])
    }
    return <>
        <ul>
            {num.map((v, i) =>
                (<li key={i}>{v.value}</li>))}
        </ul>
        <button onClick={() => add1()}>push</button>
        <br/>
        <button onClick={() => add2()}>reverse</button>

    </>
}

高阶方式

export default function App() {
    let [num, setNum] = useState({
        first: 0,
    })
    const clickOne = str => {
        setNum({...num, [str]: num.first + 1})
    }
    return <>
        <button onClick={() => clickOne('first')}>First {num.first}</button>
    </>
}

组件通信

无状态父=>无状态子

父
export const Four = (props) => {
    const list = [
        { title: 'A Christmas Carol', author: 'Charles Dickens' },
        { title: 'The Mansion', author: 'Henry Van Dyke' }];
    const clicks = (e) => {
        console.log(e.target.value);
    }

    return (<>
        xxx
        {list.map((v,i)=>{
            return <Fill title={v.title} author={v.author} inputChange={clicks} key={i}/>
        })}
    </>)
}

=========
const Fill = props => {

    return (<>
        {/*<App/>*/}
        <h1>{props.title}</h1>
        <h1>{props.author}</h1>
        <input type="text" onChange={props.inputChange}/>
    </>)
}

useState 实现增删改

import React, {useState} from 'react';
import Headers from "./header/header";

function App() {
    const [articles, setArticles] = useState([{
        id: 1,
        name: 'name1',
        hide: true
    }, {
        id: 2,
        name: 'name2',
        hide: true
    }, {
        id: 3,
        name: 'name3',
        hide: true
    }])
    const deleteAti = (id) => {
        setArticles(articles.filter(val => val.id !== id))
    }
    const addAti = () => {
        let id = articles.slice(-1)[0].id + 1;
        setArticles([
            ...articles,
            {
                id: id,
                name: 'name' + id,
                hide: true
            }
        ])
    }
    const hideEdit = id => {
        let update=[...articles];
        let index = articles.findIndex(val => val.id===id);
        let hide=articles[index].hide;
        update[index]={...articles[index],hide: !hide}
        return setArticles(update)
    }
    return (<div>
            <Headers/>
            <ul>
                {articles.map((v, i) => {
                    return <li key={i}>
                        {v.hide&&(<div>{v.name}</div>)}
                        <button onClick={() => deleteAti(v.id)}>删除</button>
                        <button onClick={() => addAti(v.id)}>增加</button>
                        <button onClick={()=>hideEdit(v.id)}>隐藏</button>
                    </li>
                })}
            </ul>
        </div>
    );
}

export default App;

生命周期

getDerivedStateFromProps 接受新属性

render setState 发生变化

componentDidMount 调用DOM

shouldComponentUpdate

  • 提高性格(为啥)

实例被创建并插入DOM中时,经历的生命周期

getDerivedStateFromProps

constructor() 
static getDerivedStateFromProps()
render()
componentDidMount()
static getDerivedStateFromProps(props, state)
当prop static发生变化
export default class Headers extends Component {
    state = {
        error: null,
        users: []
    }

    constructor(props) {
        super(props);
    }

    static defaultProps = {
        loading: 'loading'
    }

    componentDidMount() {
        setTimeout(()=>{
            this.setState({
                error: null, users: [
                    {id: 1, sex: '男1'},
                    {id: 2, sex: '男2'},
                    {id: 3, sex: '男3'},
                    {id: 4, sex: '男4'},
                ]
            })
            
        },5000)

    }

    static getDerivedStateFromProps(props, state) {
        return {...state, loading: state.users.length === 0 ? props.loading : null}
    }

    render() {
        let {loading, users} = this.state;
        return <>
            <h1>headers</h1>
            {loading&&<div>loading</div>}
            <ul>
                {users.map((v,i)=>{
                    return <li key={i}>{v.sex}</li>
                })}
            </ul>
        </>
    }
}

shouldComponentUpdate

返回等于true或者false,true指的是进行重新渲染,false指的是不需要重新渲染

   shouldComponentUpdate(nextProps, nextState, nextContext) {
        // 变化后的新数据,比如 5s后更新的数据
        console.log(nextProps);
        console.log(nextState);
        return true
    }

getSnapshotBeforeUpdate

DOM可能发生改变捕获某些信息

getSnapshotBeforeUpdate componentDidUpdate 应该一起用,不然报错

当DOM发生变化的时候会触发这个生命周期

 getSnapshotBeforeUpdate(prevProps, prevState) {
        // 这个是dom 发生变化的时候,返回前面的prop,state 的状态
     	console.log(prevProps);
        console.log(prevState);
        return null
    }
    componentDidUpdate(){
        
    }

案例

export default class Headers extends Component {
    state = {
        error: null,
        users: []
    }

    constructor(props) {
        super(props);
    }
    getSnapshotBeforeUpdate(prevProps, prevState) {
        console.log(prevProps);
        console.log(prevState);
        return null
    }
    componentDidUpdate(){

    }

    static defaultProps = {
        loading: 'loading'
    }

    componentDidMount() {
        setTimeout(()=>{
            this.setState({
                error: null, users: [
                    {id: 1, sex: '男1'},
                    {id: 2, sex: '男2'},
                    {id: 3, sex: '男3'},
                    {id: 4, sex: '男4'},
                ]
            })

        },5000)

    }

    static getDerivedStateFromProps(props, state) {
        return {...state, loading: state.users.length === 0 ? props.loading : null}
    }

    render() {
        let {loading, users} = this.state;
        return <>
            <h1>headers</h1>
            {loading&&<div>loading</div>}
            <ul>
                {users.map((v,i)=>{
                    return <li key={i}>{v.sex}</li>
                })}
            </ul>
        </>
    }
}

我们会发现当数据添加上去的时候,返回的之前的props,state

{loading: "loading"}
{error: null, users: Array(0), loading: "loading"}

getSnapshotBeforeUpdate和componentDidUpdate一起使用

可以理解用处,类似做拿到上一次的状态进行操作

getSnapshotBeforeUpdate(prevProps, prevState) {
        return {foo:1}
    }
    componentDidUpdate(prevProps, prevState, snapshot){
        console.log(snapshot);
        // {foo: 1}   当数据更新的时候,或者数据发生变化的时候
    }
// 从上级传过来的return,第三个参数componentDidUpdate

拿到DOM节点

 constructor(props) {
        super(props);
        this.textInput=React.createRef();
    }

<div ref={this.textInput}></div>

当数据更新时,给更新的dom添加背景颜色

getSnapshotBeforeUpdate(prevProps, prevState) {  1
        //拿到dom节点
        // console.log(this.textInput.current );
        //这个拿到之前的状态
        console.log(this.textInput.current.offsetHeight);
        return {boxColor:this.textInput.current.offsetHeight>20}
    }
    componentDidUpdate(prevProps, prevState, snapshot){ 2
        // 这个是拿到更新后的状态
        console.log(this.textInput.current.offsetHeight);
    }

分析,我们会发现当数据更新了,1拿到的是没有更新前的dom,2拿到了更新后的dom,1和2可以根据状态进行更新值

报错边界

请使用 static getDerivedStateFromError() 渲染备用 UI ,使用 componentDidCatch() 打印错误信息

class ErrorBoundary extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            hasError: false
        }
    }
    componentDidCatch(err, info) {
        this.setState({hasError: true})
    }
    render() {
        if(this.state.hasError) {
        
            return (
                <div>Error occurred.</div>
            )
        } else {
         
            return this.props.children
        }
    }
}

<ErrorBoundary>
    <App />
</ErrorBoundary>

比如页面报错了,直接让他显示报错的页面

try catch 类似

区别

  • getDerivedStateFromError() 渲染备用UI
  • componentDidCatch() 打印错误信息
类型 getDerivedStateFromError componentDidCatch
指令其他操作 不可以 可以
调用时间 渲染阶段调用 "提交"阶段被调用
参数 err err,info

componentWillUnmount

卸载和销毁组件的生命周期

组件dom传递

let app1=<h1>app1</h1>
let app2=<h1>app2</h1>

 <Headers {...{app1,app2}}/>

===========
export default class Headers extends Component {
		
	render() {
        let {app1,app2}=this.props
        return <>
            {app1}
            {app2}
        </>
    }
}     
posted @ 2020-08-26 10:55  猫神甜辣酱  阅读(182)  评论(0编辑  收藏  举报