美文网首页
react 学习笔记

react 学习笔记

作者: _旁观者_ | 来源:发表于2020-04-12 17:17 被阅读0次

    环境搭建
    • 创建脚手架 工具
    npx create-react-app my-app
    cd my-app
    npm start
    

    问题
    1 缺少 this.state 报错

    每个constructor 必须赋值 this.state

    2 对传值的 state 的进行类型检测

    https://zh-hans.reactjs.org/docs/typechecking-with-proptypes.html#gatsby-focus-wrapper

    3 props render states 的更新
    • 当组件的state 或 props 变化时, render函数就会被重新执行
    • 父组件的render 执行时,子组件的render 也将重新执行(因为父组件render时 有组件)
    4 ref 用法
    import React, { Component, Fragment} from 'react';
    
    class Todolist extends Component {
    
        constructor(props) {
            super(props);
            this.state = {
                inputValue: ''
            }
        }
        render () {
            return (
                <Fragment>
                    <div>
                        <input type="text" onChange={this.handleChange}
                            ref={(input) => { this.input = input}}/>
                    </div>
                </Fragment>
            )
        }
        handleChange (event) {
            this.setState({inputValue: this.input.value})
            // 注:this.setstate 是异步的,再用ref时,最好卸载 this.setstate的回调里
            //this.setState({}, () => {
               // console.log('sdsssssss')
           // })
        }
    }
    
    export default Todolist
    

    __

    https://www.jianshu.com/p/41deb68b26ed

    5 生命周期函数
        // 组件被更新之前调用, turn false 终止下面函数执行,return true才继续render函数
        shouldComponentUpdate() { }
       // 组件更新之前,shouldComponentUpdate 之后执行(必须返回true才执行)
        componentWillUpdate() { }
    
        // 页面挂载之前执行, 只执行一次
        componentWillMount() {}
        //  页面挂载执行,执行多次  state 改变render 执行
        render() {}
        // 页面挂载之后执行, 只执行一次
        componentDidMount() {}
    
       // 组件更新之后,shouldComponentUpdate 之后执行(必须返回true才执行),componentWillUpdate 之后, render函数之后,
        componentDidUpdate() { }
    
       // 从父组件接受了参数,并且父组件的render 函数 `重新` 被执行了就会被执行
        componentWillReceiveProps() { }
    
       // 组件即将被注销时,执行
        componentWillUnmount() { }
    
    生命周期函数
    • 请求接口 可以放在 componentDidMount componentWillMount 或 constructor , 不过建议放在 componentDidMount 中
    6 优化子组件
    • 如果父组件数据发生变化,不管对子组件是否有影响,子组件都会重新渲染
    • 可以通过 shouldComponentUpdate 进行优化
    import React, { Component} from 'react';
    
    class TodolistItem extends Component {
    
        constructor(props) {
            super(props);
            this.state = {}
        }
    
        render () {
            console.log(',,,,')
            return (
                <li onClick={this.handleClick}>
                    {this.props.content}
                </li>
            )
        }
    
        // props 参数发生变化才更新dom
        shouldComponentUpdate (nextProps, nextState) {
            // nextProps 将要传的 props  nextState 将要更改的 states
            return nextProps.content !== this.props.content ? true : false
        }
    }
    };
    
    7 过度属性
    npm install react-transition-group --save
    
    import React, { Component, Fragment} from 'react';
    import './app.css'
    import { CSSTransition } from 'react-transition-group';
    
    class App extends Component {
    
      constructor (props) {
        super(props);
        this.state= {
          show: true
        }
    
        this.toggleFunc = this.toggleFunc.bind(this); // 函数中要用 this.setstate, 要更改指针
      }
    
      render () {
        return (
          <Fragment>
            {/* <div className={this.state.show ? 'show' : 'hide'}>hello world</div> */}
            <CSSTransition
              in={this.state.show}
              timeout={1000}
              classNames="fade"
              unmountOnExit 
              onEnter={(el) => {el.style.color = 'red'}}
            >
              <div>hello world</div>
            </CSSTransition>
            <button onClick={this.toggleFunc}>toggle</button>
          </Fragment>
        )
      }
    
      toggleFunc () {
        this.setState({
          show: this.state.show ? false : true
        })
      }
    }
    
    export default App;
    
    
    /* 进场前一刻的动画 */
    .fade-enter, .fade-appear {
        opacity: 0;
    }
    /* 进场后到动画执行完的过程之间的动画 */
    .fade-enter-active, .fade-appear-active {
        opacity: 1;
        transition: opacity 1s ease-in;
    }
    /* 动画执行完程样式 */
    .fade-enter-done {
        opacity: 1;
    }
    /* 出场前一刻的动画 */
    .fade-exit {
        opacity: 1;
    }
    /* 出场到动画执行完的过程之间的动画 */
    .fade-exit-active {
        opacity: 0;
        transition: opacity 1s ease-in;
    }
    /* 出画执行完程样式 */
    .fade-exit-done {
        opacity: 0;
    }
    

    参考

    8 redux
    npm install --save redux
    
    文件目录
    • index.js
    import { createStore } from 'redux';
    import reducer  from './reducer.js'
    
    const store = createStore(reducer);
    
    export default store;
    
    • reducer.js
    
    const defaultState = {
        inputValue: '111',
        list: [1221,232]
    }
    
    // state 当前的state 数据, action 是 dispatch 触发过来的一个对象
    // reducer 可以拷贝state  不能更改state
    export default (state = defaultState, action) => {
        // console.log(state, action)
        if (action.type === CHANGE_INPUT_VALVUE) {
            const newState = JSON.parse(JSON.stringify(state))
            newState.inputValue = action.value
            return newState
        } 
        if (action.type === ADD_INPUT_VALVUE) {
            const newState = JSON.parse(JSON.stringify(state))
            newState.list.push(action.value)
            newState.inputValue = ''
            return newState
        }
        if (action.type === DELETE_INPUT_VALVUE) {
            const newState = JSON.parse(JSON.stringify(state))
            newState.list.splice(action.value, 1)
            return newState
        }
        return state
    }
    
    • actionType.js
    // todolist
    export const CHANGE_INPUT_VALVUE = 'CHANGE_INPUT_VALVUE'
    export const ADD_INPUT_VALVUE = 'ADD_INPUT_VALVUE'
    export const DELETE_INPUT_VALVUE = 'DELETE_INPUT_VALVUE'
    
    • actionCreater.js
    import { CHANGE_INPUT_VALVUE, ADD_INPUT_VALVUE, DELETE_INPUT_VALVUE} from './actionType.js'
    
    export const inputChange = (value) => {
        return {
            type: CHANGE_INPUT_VALVUE,
            value: value
        }
    }
    
    export const inputAdd = (value) => {
        return {
            type: ADD_INPUT_VALVUE,
            value: value
        }
    }
    
    export const inputDelete = (value) => {
        return {
            type: DELETE_INPUT_VALVUE,
            value: value
        }
    }
    
    • 获取redux 中的数据
    import store from './store'
    store.getState() // 获取数据
    
    • 更改数据
    import store from './store'
    import { inputChange, inputAdd, inputDelete } from './store/actionCreater.js'
    
    // 创建action
    const action = inputChange(event.target.value)
    // 通过 store.dispatch 方法去修改 redux 中的数据
    store.dispatch(action)
    
    • 实现redux 数据更新 自动刷新页面
    import store from './store'
    import React, { Component } from 'react';
    
    class xxx extends Component {
        constructor(props) {
            super(props);
            this.state = store.getState()
            this.handleChange = this.handleChange.bind(this); // 函数中要用 this.setstate, 要更改指针
    
            store.subscribe(this.dataChange) // store.subscribe 订阅 当store中数据发生变化时,就会执行指定的函数
        }
    
        render () { return (...) }
    
        dataChange () { 
            this.setState(store.getState()) 
        }
    }
    
    export default xxx
    
    
    9 react 无状态组件

    无状态组件就是只有render 函数的ui组件

    • 相比较于 ui 组件 性能高(因为本质上是函数)
    // import React, { Component } from 'react';
    import React from 'react';
    import { List, Input, Button } from 'antd';
    
    // 无状态组件 就是个函数
    const TodoListUi = (props) => {
        return (
            <div>
                    <div>
                        <Input placeholder="输入内容" 
                            value={props.inputValue} 
                            onChange={props.handleChange}
                            style={{width: '300px'}}
                        />
                        <Button onClick={props.addDate} type="primary">提交</Button>
                    </div>
                    <List size="small"
                        bordered
                        style={{width: '300px'}}
                        dataSource={props.list}
                        // 函数传值时, onClick={() => {this.props.handleDelete(index)}} 绑定里一个函数来执行 this.props.handleDelete(index) 函数
                        renderItem={(item, index) => <List.Item onClick={() => {props.handleDelete(index)}}>{item}</List.Item>}
                    />
                </div>
        )
    }
    
    //生成的是react ui组件 包括生命周期函数 construction render 等等
    // class TodoListUi extends Component {
    //     render () {
    //         return (
    //             <div>
    //                 <div>
    //                     <Input placeholder="输入内容" 
    //                         value={this.props.inputValue} 
    //                         onChange={this.props.handleChange}
    //                         style={{width: '300px'}}
    //                     />
    //                     <Button onClick={this.props.addDate} type="primary">提交</Button>
    //                 </div>
    //                 <List size="small"
    //                     bordered
    //                     style={{width: '300px'}}
    //                     dataSource={this.props.list}
    //                     // 函数传值时, onClick={() => {this.props.handleDelete(index)}} 绑定里一个函数来执行 this.props.handleDelete(index) 函数
    //                     renderItem={(item, index) => <List.Item onClick={() => {this.props.handleDelete(index)}}>{item}</List.Item>}
    //                 />
    //             </div>
    //         )
    //     }
    // }
    
    export default TodoListUi
    
    10 redux-thunk 处理异步数据
    文件目录
    • store/index.js
    import { createStore, applyMiddleware } from 'redux';
    import thunk from 'redux-thunk';
    import reducer  from './reducer.js'
    
    const store = createStore(reducer, applyMiddleware(thunk));
    
    export default store;
    
    • store/actionCreater.js 添加
    ...
    export const getTodoList = () => {
        // 添加 redux-thunk 后, 返回的函数自动就带 dispatch 了
        return (dispatch) => {
            setTimeout(() => {
                dispatch(initTodoList([1,2,3,4,5,6]))
            }, 1000);
        }
    }
    ...
    
    • store/reducer.js 添加
    ...
    if (action.type === INIT_TODOLIST) {
            const newState = JSON.parse(JSON.stringify(state))
            newState.list = action.value
            return newState
        }
    ...
    
    • store/actionType.js 添加
    ...
    export const INIT_TODOLIST = 'INIT_TODOLIST'
    ...
    
    • 组件使用
    ...
    componentDidMount () {
            store.dispatch(getTodoList())
        }
    ...
    

    https://github.com/reduxjs/redux-thunk


    11 搭建react 项目
    • 创建 react 项目
     npm create-react-app my-app
    

    https://reactjs.bootcss.com/docs/create-a-new-react-app.html

    • 插件
    npm install styled-components
    

    https://www.npmjs.com/package/styled-components

    作为公共样式使用
    文件目录
    style.js
    import { createGlobalStyle } from 'styled-components'
    
    export const GlobalStyled = createGlobalStyle`
    html, body, div, span, applet, object, iframe,
    h1, h2, h3, h4, h5, h6, p, blockquote, pre,
    a, abbr, acronym, address, big, cite, code,
    del, dfn, em, img, ins, kbd, q, s, samp,
    small, strike, strong, sub, sup, tt, var,
    b, u, i, center,
    dl, dt, dd, ol, ul, li,
    fieldset, form, label, legend,
    table, caption, tbody, tfoot, thead, tr, th, td,
    article, aside, canvas, details, embed, 
    figure, figcaption, footer, header, hgroup, 
    menu, nav, output, ruby, section, summary,
    time, mark, audio, video {
        margin: 0;
        padding: 0;
        border: 0;
        font-size: 100%;
        font: inherit;
        vertical-align: baseline;
    }
    /* HTML5 display-role reset for older browsers */
    article, aside, details, figcaption, figure, 
    footer, header, hgroup, menu, nav, section {
        display: block;
    }
    body {
        line-height: 1;
        background: green;
    }
    ol, ul {
        list-style: none;
    }
    blockquote, q {
        quotes: none;
    }
    blockquote:before, blockquote:after,
    q:before, q:after {
        content: '';
        content: none;
    }
    table {
        border-collapse: collapse;
        border-spacing: 0;
    }
    `
    

    app.js

    import React, { Component } from 'react';
    import { GlobalStyled } from './style.js'
    
    class App extends Component {
        render() {
            return (
                <div className={'fontSize'}>
                    {/* 样式引入 */}
                    <GlobalStyled/>
                    hello world
                </div>
            )
        }
    }
    
    export default App
    
    作为组件使用
    文件

    index.js

    import React, { Component } from 'react';
    import {
        HeaderContent,
        Logo,
        Nav
    } from './style';
    
    class Header extends Component {
        render () {
            return (
                <HeaderContent>
                    <Logo/>
                    <Nav/>
                </HeaderContent>
            )
        }
    }
    
    export default Header;
    

    style.js

    import styled from 'styled-components';
    import logo from '../../static/logo.png'
    
    export const HeaderContent = styled.div`
        position: relative;
        height: 58px;
        width: 100%;
        border-bottom: 1px solid #f0f0f0;
    `
    
    export const Logo = styled.div`
        position: absolute;
        height: 100%;
        width: 100px;
        float: left;
        background: url(${logo});
        background-size: contain;
    `
    
    export const Nav = styled.div`
        height: 100%;
        width: 960px;
        margin: 0 auto;
        background: red;
    `
    
    • react react-redux 安装使用
    npm install redux react-redux --save-dev
    

    app.js文件 (入口文件)

    ...
    import {Provider} from 'react-redux'
    import store from './store'
    
    class App extends Component {
        render() {
            return (
                <Provider store={store}>
                    入口文件
                </Provider>
            )
        }
    }
    
    export default App
    

    store 文件结构

    文件结构

    index.js

    import { createStore } from 'redux';
    import reducer  from './reducers/index.js'
    
    const store = createStore(reducer);
    
    export default store;
    

    actionType.js

    export const FOUCESTATE = 'FOUCESTATE'
    export const BLURSTATE = 'BLURSTATE'
    

    actionCreater.js

    import { FOUCESTATE, BLURSTATE } from './actionType.js'
    
    export const fouceInput = () => {
        return {
            type: FOUCESTATE
        }
    }
    
    export const blurInput = () => {
        return {
            type: BLURSTATE
        }
    }
    

    reducers/headerReducer.js

    import { FOUCESTATE, BLURSTATE } from '../actionType.js'
    
    const defaultState = {
        fouce: false
    }
    
    // state 当前的state 数据, action 是 dispatch 触发过来的一个对象
    // reducer 可以拷贝state  不能更改state
    export default (state = defaultState, action) => {
        // console.log(state, action)
        if (action.type === FOUCESTATE) {
            return {
                fouce: true
            }
        } 
        if (action.type === BLURSTATE) {
            return {
                fouce: false
            }
        }
        return state
    }
    

    reducers/index.js

    import { combineReducers } from 'redux'
    import headerReducer from './headerReducer.js'
    
    export default combineReducers({
        header: headerReducer
    })
    

    组件使用

    import React, { Component } from 'react';
    import {CSSTransition} from 'react-transition-group'
    import { connect } from 'react-redux'
    import { fouceInput, blurInput } from '../../store/actionCreater.js'
    import {
        HeaderContent,
        Logo,
        Nav,
        NavItem,
        NavInput,
        Addtion,
        Button,
        SearchIcon
    } from './style';
    
    class Header extends Component {
    
        render () {
            return (
                <HeaderContent>
                    <Logo/>
                    <Nav>
                        <NavItem className='left active'>首页</NavItem>
                        <NavItem className='left'>下载APP</NavItem>
                        <SearchIcon>
                            <CSSTransition
                                in={this.props.fouce}
                                timeout={200}
                                classNames="slider"
                            >
                                <NavInput placeholder="搜索"
                                    onFocus={this.props.fouceState}
                                    onBlur ={this.props.blurState}
                                    className={this.props.fouce ?  'fouce' : ''}
                                ></NavInput>
                            </CSSTransition>
                            <span 
                                className={this.props.fouce ? 'iconfont left active' : 'iconfont left'}
                            >
                                &#xe62c;
                            </span>
                        </SearchIcon>
                        <NavItem className='right gray'>
                            <span className="iconfont">&#xe636;</span>
                        </NavItem>
                        <NavItem className='right gray'>登录</NavItem>
                    </Nav>
                    <Addtion>
                        <Button>注册</Button>
                        <Button className='active'>
                            <span className="iconfont">&#xe63a;</span>写文章</Button>
                    </Addtion>
                </HeaderContent>
            )
        }
    
    }
    
    const mapStateToProps = (state) => {
        return {
            fouce: state.header.fouce
        }
    }
    const mapDispatchToProps = (dispatch) => {
        return {
            fouceState () {
                dispatch(fouceInput())
            },
            blurState () { 
                dispatch(blurInput())
            }
        }
    }
    
    export default connect(mapStateToProps, mapDispatchToProps)(Header);
    
    • immutable 安装
    npm install immutable
    npm install redux-immutable
    

    store/reducers/headerReducer.js文件修改

    import { FOUCESTATE, BLURSTATE } from '../actionType.js'
    import { fromJS } from 'immutable'
    
    const defaultState = fromJS({
        fouce: false
    })
    
    export default (state = defaultState, action) => {
        if (action.type === FOUCESTATE) {
            // state.set('fouce', true)  是返回了一个新的对象,并不是修改原来的对象
            return state.set('fouce', true)
        } 
        if (action.type === BLURSTATE) {
            return state.set('fouce', false)
        }
        return state
    }
    

    store/reducers/index.js文件修改

    import { combineReducers } from 'redux-immutable'
    import headerReducer from './headerReducer.js'
    
    export default combineReducers({
        header: headerReducer
    })
    

    组件使用

    ...
    
    const mapStateToProps = (state) => {
        return {
            fouce: state.get('header').get('fouce')
        }
    }
    ...
    
    export default connect(mapStateToProps, mapDispatchToProps)(Header);
    

    immutable 到底干啥了

    https://github.com/immutable-js/immutable-js

    • 添加路由
    npm install react-router-dom --save-dev
    

    app.js

    ...
    import { BrowserRouter, Route } from 'react-router-dom'
    import Detail from './pages/detail'
    import Home from './pages/home'
    ...
     
    class App extends Component {
        render() {
            return (
                <Provider store={store}>
                    <div className={'fontSize'}>
                         ....
                        <Header/>
                        <BrowserRouter>
                            <div>
                                <Route path='/' exact component={Home}></Route>
                                <Route path='/detail' exact component={Detail}></Route>
                               //带参数路由
                                 <Route path='/detail/:id' exact component={Detail}></Route>
                            </div>
                        </BrowserRouter>
                    </div>
                </Provider>
            )
        }
    }
    export default App
    

    link 使用

    import { Link } from 'react-router-dom';
    
    class Lists extends PureComponent {
    
        render () {
            return (
                   <Link key={item.get('id')} to='/detail'>
                   <Link key={item.get('id')} to={'/detail/'+ item.get('id')}>
                        ....
                   </Link>
            )
        }
    }
    

    获取路由参数

    this.props.match.params // 动态路由获取参数
    

    js操作跳转路由

    • react 事件监听
    class Home extends Component {
        ...
        componentDidMount () { // 监听事件
            this.bindEvents()
        }
    
        componentWillUnmount () { // 记得移除
            window.removeEventListener('scroll', this.props.changeFlag)
        }
    
        bindEvents () {
            window.addEventListener('scroll', this.changeFlag)
        }
        changeFlag (e) {
            console.log(e)
        }
        ...
    }
    
    
    • react 组件 PureComponent

    https://www.jianshu.com/p/690444f9f2dc

    https://github.com/benzcar/jianshu-RN

    相关文章

      网友评论

          本文标题:react 学习笔记

          本文链接:https://www.haomeiwen.com/subject/omyznctx.html