React查缺补漏

1.React.createElement:根据指定的第一个参数创建一个React元素
第一个参数是必填,传入的是似HTML标签名称,eg: ul, li
第二个参数是选填,表示的是属性,eg: className
第三个参数是选填, 子节点,eg: 要显示的文本内容

class App extends React.Component{
    render(){
        return (
            <div className='head' id='header'>
                <p className='cotent'>hello react</p>
            </div>
        )
    }
}

React.createElement可以写成如下:
class App extends React.Component{
    render(){
        return(
            React.createElement(
                'div',
                {
                    className:'head',
                    id:'header'
                },
                React.createElement(
                    'p',
                    {
                        className:'cotent',
                    },
                    'hello react'
                )
            )
        )
    }
}

2.第三方包classnames
作用:可以根据对象的方式来确定样式名
前提:npm install classnames

import classNames from 'classnames';
class App extends React.Component{
    render(){
        let {color} = this.props
        return (
            <div className='head' id='header'>
                <p className={classNames('yellow',{'blue':color=='blue'},{'red':color=='red'})}>根据传参确定样式</p>
            </div>
        )
    }
}

3.React自带Fragment组件
作用:因为React语法在渲染return方法中必须有一个根标签,而有的时候根标签毫无作用,这个时候我们就可以使用Fragment组件,Fragment不会产生在DOM中产生新的标签

import React, { Component,Fragment } from 'react'
class App extends Component {
    render() {
        return (
            <Fragment>
                <Header />
                <Input />
            </Fragment>
        )
    }
}

4.向Header组件中传递Input组件的两种方式
第一种:children方式传递

import {Header, Input} from './components/index';
<Header>
     <Input />
 </Header>
 
在Header组件中
	render() {
        let {children} = this.props;
        return (
            <div>
                {
                    children
                }
            </div>
        )
    }

第二种:纯props方式

import {Header, Input} from './components/index';
<Header Input={<Input />}></Header>

在Header组件中
	render() {
        let {Input} = this.props;
        return (
            <div>
                { Input }
            </div>
        )
    }

5.React组件传值检测类型
前提:npm install prop-types

import React, { Component } from 'react'
import PropTypes from 'prop-types';
(1)类组件
export default class Header extends Component {

    // isRequired 表示必须的,如果父组件未传值就会报错
    static propTypes = {
        x: PropTypes.number.isRequired,
        y: PropTypes.number.isRequired,
    }
    
    //如果没有传值,可以给一个默认值
	static defaultProps = {
        x: 0,
        y: 0
    }
    
    render() {
        let {x,y} = this.props;
        return (
            <div>
                {x+y}
            </div>
        )
    }
}

(2)函数组件
export default function Header(){
	return (
			<div></div>
	)
}
Header.propTypes = {
	x: PropTypes.number.isRequired
}

注意:可以检验的类型
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol

作者:_123hhh
链接:https://www.jianshu.com/p/a73fb26c88b5
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

6.dangerouslySetInnerHTML
作用:如果需要渲染的字符串中包括HTML标签就可以使用dangerouslySetInnerHTML

state={
	title:'<div><div>标题</div><div>内容</div></div>',
}
<div dangerouslySetInnerHTML={{__html:this.state.title}}></div>

7.父子组件传值小技巧
使用情况:如果要传值的类型为Object并且想要在子组件中使用this.props获取的情况可以使用…运算符来传值

{
    this.state.todos.map(todo=>{
        return <Header {...todo}></Header>
    })
}

8.ref使用的几种方法
第一种:ref回调函数

	inputChange = ()=>{
        console.log(this.inputValue.value);
    }
	<input 
      ref={child=>this.inputValue=child}
       onChange={this.inputChange.bind(this)}
   />

第二种:React.createRef()

constructor(){
        super();
        this.inputRef = React.createRef();
    }
	inputChange = ()=>{
        console.log(this.inputRef.current.value);
    }
	<input 
         ref={this.inputRef}
         onChange={this.inputChange.bind(this)}
     />

9.React生命周期
在这里插入图片描述
说明:
1)getDerivedStateFromProps
返回一个对象以更新状态,或者返回null则不更新任何内容

	static getDerivedStateFromProps(props, state){
        return {name:props.name};
    }
	render() {
        let {name} = this.state;
        return (
            <div>
                {name}
            </div>
        )
    }

2)shouldComponentUpdate
返回true则表示渲染更新状态,返回false则不重新渲染;一般用于解决重复多次渲染问题,第二种解决多次渲染问题同样可以使用继承React.PureComponent。

shouldComponentUpdate(nextProps,nextState){
        return nextProps.checked !== this.props.checked .;
   }

10.全局挂载方法
使用React.Component.prototype来实现全部挂载

被全局挂载的方法:
import axios from 'axios';
let ajax = axios.create({
    baseURL: 'https://jsonplaceholder.typicode.com/'
});

export const getTodos = ()=>{
    return ajax.get('/todos');
}

实现全局挂载:
import * as getTodos from './service/index';
React.Component.prototype.http = getTodos;

使用全局挂载:
componentDidMount(){
   this.http.getTodos().then((result)=>{
        console.log(result);
    })
}

11.react-hooks
作用:不通过编写类组件的情况下,可以在组件内部使用状态(state) 和其他 React 特性(生命周期,context)的技术

import React,{useState,useEffect} from 'react';
const Counter = ()=>{
    // 相当于给count赋值为0
    const [count,setCount]=useState(0);

    // 相当于ComponentDidMount和ComponentDidUpdate
    useEffect(()=>{
        console.log('useEffect')
    })
    return(
        <div>
            <button onClick={()=>{setCount(count-1)}}>-</button>
            <span>{count}</span>
            <button onClick={()=>{setCount(count+1)}}>+</button>
        </div>
    )
}

12.Context
作用:Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。

import React,{Fragment,createContext} from 'react';
import ReactDOM from 'react-dom';

const {Provider,Consumer:CounterConsumer} = createContext();

class CounterProvider extends React.Component{
    constructor(){
        super();
        this.state={
            count:1000
        }
    }

    increment = ()=>{
        this.setState({
            count: this.state.count+1
        })
    }

    decrement = ()=>{
        this.setState({
            count: this.state.count-1
        })
    }
    render(){
        return(
            <Provider value={
                {
                    count:this.state.count,
                    onIncrement:this.increment,
                    onDecrement:this.decrement
                }
            }>
                {this.props.children}
            </Provider>
        )
    }
}

class App extends React.Component{
    render(){
        return (
            <Fragment>
                <CountBtn type='decrement'>-</CountBtn>
                <Counter />
                <CountBtn type='increment'>+</CountBtn>
            </Fragment>
        )
    }
}

class CountBtn extends React.Component{
    render(){
        return (
            <CounterConsumer>
                {
                    ({onIncrement,onDecrement})=>{
                        const handleClick = this.props.type==='increment'?onIncrement:onDecrement;
                        return <button onClick={handleClick}>{this.props.children}</button>
                    }
                }
            </CounterConsumer>
        )
    }
}

class Counter extends React.Component{
    render(){
        return (
            <CounterConsumer>
                {
                    (args)=>{
                        return <span>{args.count}</span>
                    }
                }
            </CounterConsumer>
        )
    }
}

ReactDOM.render(
    <CounterProvider>
        <App />
    </CounterProvider>
    ,
    document.getElementById('root')
)

13.高阶组件HOC
高阶组件是参数为组件,返回值为新组件的函数。

高阶组件:
import React from 'react';
let copyRight = (App)=>{
    return (
        class CopyRight extends React.Component{
            render(){
                return (
                    <div>
                        <App {...this.props} />
                        <h1>这里是高阶组件</h1>
                    </div>
                )
            }
        }
    )
}

export default copyRight;

使用高阶组件:
import React, { Component } from 'react'
import CopyRight from './copyRight';
import Another from './another';

class App extends Component {
    render() {
        return (
            <div>
                <h1>这是App组件</h1>
                <Another name='wq' />
            </div>
        )
    }
}

export default CopyRight(App);

改为装饰器的写法:
步骤:
1)npm install react-app-rewired --save-dev
react-app-rewired:在不使用’eject’且未创建react-scripts分支的情况下,调整create-react-app webpack配置。
2)修改package.json文件:

修改:
"scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  为:
  "scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-scripts eject"
  },

3)在根目录下新建config-overrides.js

const { override, addDecoratorsLegacy } = require('customize-cra');
module.exports = override(
    addDecoratorsLegacy()
);

4)npm install customize-cra --save-dev
// 将类和对象装饰器编译为ES5
npm install @babel/plugin-proposal-decorators --save-dev

高阶组件装饰器写法:

import React, { Component } from 'react'
import CopyRight from './copyRight';

@CopyRight
class Another extends Component {
    render() {
        return (
            <div>
                <h3>作者:{this.props.name}</h3>
            </div>
        )
    }
}

export default Another;

14.状态管理

搭建简单的redux

index.js文件
import React from 'react';

import ReactDOM from 'react-dom';

import { Provider } from 'react-redux';

import App from './App';

import store from './store';

ReactDOM.render(
    <Provider store={store}>
        <App />
    </Provider>,
    document.getElementById('root')
)

store.js文件
import {createStore,applyMiddleware} from 'redux';

import thunk from 'redux-thunk';

import rootReducers from './reducers/index';

export default createStore(
    rootReducers,
    applyMiddleware(thunk),    // 解决异步action问题
)

reducers.index文件
import { combineReducers } from 'redux';

import BlogListReducer from './BlogList';

export default combineReducers({
    BlogListReducer,
})

使用redux
import React, { Component } from 'react'
import {connect} from 'react-redux';
import * as actions from '../../actions/BlogList';
class BlogList extends Component {

    componentDidMount(){
        this.props.startFetchData();
    }

    render() {
        let {blogList} = this.props;
        return (
            <div>
               {
                   blogList.map(item=>{
                        return <div key={item.id}>{`用户ID:${item.userId},用户标题:${item.title}`}</div>
                   })
               } 
            </div>
        )
    }
}

let mapStateToProps = (state)=>{
    return {
        blogList:state.BlogListReducer.data
    } 
}

export default connect(mapStateToProps,actions)(BlogList);

15.实现导出Excel
前提:npm install xlsx

import XLSX from 'xlsx';
const ws = XLSX.utils.aoa_to_sheet([['a','b'],[1,2]]);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb,ws,'SheetJS');
XLSX.writeFile(wb,'WQ.xlsx');

16.简易redux

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div>
        <button onclick="store.dispatch({type: 'JIAN', n: 1})">-</button>
        <span id='count'>0</span>
        <button onclick="store.dispatch({type: 'JIA', n: 1})">+</button>
    </div>
</body>
<script>
    const countDisplay = document.getElementById('count');
    const countState = {
        count: 5
    }

    const changeState = (state, action) => {
        if (!state) {
            return countState;
        }
        switch (action.type) {
            case "JIAN":
                return {
                    ...state,
                    count: state.count - action.n
                }
                break;
            case "JIA":
                return {
                    ...state,
                    count: state.count + action.n
                }
                break;
            default:
                return state;
        }
    }

    const createStore = (changeState) => {
        let state = null;
        const getState = () => state
        const listeners = []
        const subscribe = (listener) => listeners.push(listener)

        const dispatch = (action) => {
            state = changeState(state, action)
            listeners.forEach(listener => listener())
        }

        dispatch({})

        return {
            getState,
            dispatch,
            subscribe
        }
    }

    const store = createStore(changeState);

    const renderCount = () => {
        countDisplay.innerHTML = store.getState().count
    }

    renderCount();

    store.subscribe(renderCount)

</script>

</html>

17.判断React组件是否销毁

this.updater.isMounted(this)

18. memo useMemo useCallback

1) memo:作用相当于PureComponent
import React, { memo } from 'react'
const Child = memo(() => {
    const date = new Date()
    return <div>当前时间:{date.getHours()} {date.getMinutes()} {date.getSeconds()}</div>
}, (pre, next) => {
    // 返回true代表不更新
    return true
})

2)useMemo
const Child = memo((props) => {
    const date = new Date()
    return <div>当前时间:{date.getHours()} {date.getMinutes()} {date.getSeconds()}</div>
})

const Parent = () => {
    const [count, setCount] = useState(0)
    const [testCount, setTestCount] = useState(0)

    // 只有当count发生变化时,timeoption才会变化,才会引发自组件重新渲染
    const timeoption = useMemo(
        ()=>{
            return {
                count
            }
        },
        [count]
    )
    return (
        <div>
            <p>{count}</p>
            <button onClick={
                () => {
                    setCount(count + 1)
                }
            }>+1</button>
            <button onClick={
                () => {
                    setTestCount(testCount + 1)
                }
            }>+1</button>
            <Child count={timeoption} />
        </div>
    )
}

3)useCallback
const Child = memo((props) => {
    return (
        <Fragment>
            <input onChange={props.onChange} />
        </Fragment>
    )
})

const Parent = () => {
    const [text, setText] = useState('')

    const onChange = useCallback(
        e => {
            setText(e.target.value)
        },
        []
    )

    return (
        <div>
            <p>{text}</p>
            <Child onChange={onChange} />
        </div>
    )
}

19.自定义hooks

customHooks.js

import { useState, useEffect } from 'react'

export const useWindowSizeHook = () => {
    const [width, setWidth] = useState(0)
    const [height, setHeight] = useState(0)

    useEffect(() => {
        setWidth(document.documentElement.clientWidth)
        setHeight(document.documentElement.clientHeight)
    }, [])

    useEffect(() => {
        const handleResize = () => {
            setWidth(document.documentElement.clientWidth)
            setHeight(document.documentElement.clientHeight)
        }
        window.addEventListener('resize', handleResize, false)
        return () => window.removeEventListener('resize', handleResize, false)
    }, [])

    return [width, height]
}

import { useWindowSizeHook } from './customHooks'
const Parent = () => {
    const [width, height] = useWindowSizeHook()

    return (
        <div>
            <p>宽度:{width}</p>
            <p>高度:{height}</p>
        </div>
    )
}

20.useReducer、useContext

import React, { useReducer, useContext, createContext } from 'react'

const CTX = createContext(null)

const reducer = (state, action) => {
    switch(action.type){
        case 'ADD': return state + 1;
        case 'SUB': return state - 1;
        default: return state;
    }
}

const Child = () => {
    const [ count, dispatch ] = useContext(CTX)

    return (
        <div>
            <p>count:{count}</p>
            <button
                onClick={
                    ()=>{ dispatch({ type: 'SUB' }) }
                }
            >-1</button>
            <button
                onClick={
                    ()=>{ dispatch({ type: 'ADD' }) }
                }
            >+1</button>
        </div>
    )
}

const Parent = () => {
    const [ count ] = useContext(CTX)
    return (
        <div>
            <p>count:{count}</p>
            <Child />
        </div>
    )
}

const App = () => {
    // 第一个参数参数传入reducer,第二个参数传入初始值
    const [ count, dispatch ] = useReducer(reducer, 20)
    return (
        <CTX.Provider value={[ count, dispatch ]}>
            <Parent />
        </CTX.Provider>
    )
}

export default App

21.useSelector、useDispatch代替connect

目录结构:
	component
		action.js (1)
		Form.js (2)
		reducer.js (3)
	store
		configureStore.js (4)
		reducer.js (5)
	App.js (6)
	index.js (7)
(1)
export const TYPE = {
    UPDATA_NAME: 'UPDATA_NAME',
    UPDATA_TEL: 'UPDATA_TEL'
}
export const updateTel = (tel) => ({
    type: TYPE.UPDATA_TEL,
    payload: {
        tel
    }
})
export const updateName = (name) => ({
    type: TYPE.UPDATA_TEL,
    payload: {
        name
    }
})
(2)
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { updateName, updateTel } from './action'
export default () => {
    const dispatch = useDispatch()
    
    const formData = useSelector(state => {
        return state.formReducer
    })

    console.log('formData', formData)
    
    return (
        <div>
            姓名: <input onChange={(e)=> {dispatch(updateName(e.target.value))}} /> <br />
            电话: <input onChange={(e)=> {dispatch(updateTel(e.target.value))}} />
        </div>
    )
}
(3)
import { TYPE } from './action'
const initState = {
    tel: '',
    name: ''
}

export default (state, action) => {
    const { type, payload } = action
    if(Object.values(TYPE).includes(type)) return {...state, ...payload}
    return state || initState
}
(4)
import { createStore, applyMiddleware } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension'
import thunk from 'redux-thunk'
import reducer from './reducer'

export default () => {
    const middlewares = [thunk]
    const enhancers = applyMiddleware(...middlewares)
    const composedEnhancers = composeWithDevTools(...[enhancers])
    const store = createStore(reducer, composedEnhancers)
    return store
}
(5)
import { combineReducers } from 'redux'
import formReducer from '../components/reducer'

export default combineReducers({
    formReducer
})
(6)
import React from 'react'

import Form from './components/Form'

const App = () => {
    return (
        <Form />
    )
}

export default App
(7)
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import configureStore from './store/configureStore'
import App from './App'

const store = configureStore()

ReactDOM.render(
    <Provider store={store}>
        <App />
    </Provider>,
    document.getElementById('root')
)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值