笔记react 学习与记录

Posted ThinkerWing

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了笔记react 学习与记录相关的知识,希望对你有一定的参考价值。

基础精讲

起步

npm i -g create-react-app
create-react-app todolist
npm run start

src-> App.js、index.js

import {Component} from 'react';
//等价于
import React from 'react';
const Component = React.Component

所以app.js可以这么写

import React,{Component} from 'react';

class App extends Component {
  render() {
    return (
      <div>
       hello world
      </div>
    );
  }
}

export default App;

通过
import React from ‘react’;
编译react中的jsx语法

index入口文件

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';


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

响应式设计思想和事件绑定

1.js表达式需要花括号包裹
value={this.state.inputValue}
2.事件绑定需要bind(this)对函数作用域进行变更
onChange={this.hanleInputChange.bind(this)}
3.改变数据内容不能直接改 需要setState 向里面传入对象的形式
this.setState({
inputValue:e.target.value
})

补充删除功能

import React,{ Component,Fragment } from 'react';
class ToDoList extends Component {
    constructor(props) {
        super(props);
        this.state = {
            inputValue: '',
            list: []
        }
    }
    render() {
        return (
            <Fragment>
                <div>
                    <input 
                    value={this.state.inputValue}
                    onChange={this.hanleInputChange.bind(this)}
                    />
                    <button onClick={this.hanleBtnClick.bind(this)}>提交</button>  
                </div>
                <ul>
                    {
                        this.state.list.map((item, index) => {
                            return ( 
                            <li 
                            key = {index}
                            onClick={this.handleItemDelete.bind(this, index)}>
                                
                           {index}---{item}
                            </li>
                            )
                        })
                    }
                </ul>
            </Fragment>
        )
    }
    hanleInputChange(e) {
        this.setState({
            inputValue:e.target.value
        })
    }
    hanleBtnClick() {
        this.setState({
            list:[...this.state.list, this.state.inputValue],
            inputValue: ''
        })
    }
    handleItemDelete(index) {
        console.log(index);
        //immutable概念
        //state 不允许我们做任何改变 所以拷贝修改副本
        // list.state.list.splice(index, 1) 这样子的写法是不行的 
        const list = [...this.state.list] //是一份拷贝
        list.splice(index, 1)
        //react 改变数据要求调用setState
        this.setState({
            list: list 
        })
    }
}
export default ToDoList;

计数器增减和循环案例

import React,{ Component,Fragment } from 'react';
import  './style.css'
class ToDoList extends Component {
    constructor(props) {
        super(props);
        this.state = {
          movies:[1,2,3,4],
          count:0
        }
    }
    render() {
        const liArray = []
        for (let movies of this.state.movies){
            liArray.push(<li>{movies}</li>)
        }
        return (
            <div>
                <ul>
                    {liArray}
                </ul>
                <div>
                    {this.state.count}
                    <button onClick={this.a.bind(this)}>+</button>
                    <button onClick={this.b.bind(this)}>-</button>
                </div>
            </div>
        )
           
        
    }
    a() {
        this.setState({
            count:this.state.count+1
        })
    }
    b() {
        this.setState({
            count:this.state.count-1
        })
    }

}
export default ToDoList;

写法注意

1.注释
{
/*jsx里面写注释的方式 */
}

2.css要用className 不然容易被当成类
否则

解决方式

3.htmlFor
react 中 for会和for循环产生歧义 所以label 中 for要使用htmlFor

4.不能直接显示数据类型
设计原因
{flag ? ‘a’ : null}会生成很多null 或空字符串 不如不渲染
解决方法 + ‘ ’
{this.state.test+ ‘ ’}

class ToDoList extends Component {
constructor(props) {
    super(props);
    this.state = {
      age:18,
      name:'a',
      names:['a','b','c'],
      test1:null,
      test2:undefined,
      test3:true
    }
}
render() {
    
    return (
        <div>
      <div>{this.setState.name}</div>
            <div>{this.setState.age}</div>
            <div>{this.setState.names}</div>
            <div>{this.setState.test1}</div>
            <div>{this.setState.test2}</div>
            <div>{this.setState.test3}</div>
        </div>
    )
       
    
}

}`

面向对象

 		class Person {
            constructor(name, age) {
                this.name = name;
                this.age = age;
            }
            running() {
                console.log('runnning');
            }
        }
        class Student extends Person {
            constructor(name, age, sno) {
                super(name, age);
                this.sno = sno;
            }
        }
        const stu = new Student('a', 18, 1)
        console.log(stu.name, stu.age, stu.sno);
        stu.running();

拆分组件与组件间传值

父组件向子组件传递数据

通过标签上的属性形式传递 既可以传递数据又可以传递方法

 				{
                        this.state.list.map((item, index) => {
                            return ( 
                            <div>
                            <TodoItem content={item}/>

                            { /*<li 
                            key = {index}
                            onClick={this.handleItemDelete.bind(this, index)}
                            dangerouslySetInnerHTML={{__html: item}}>       
                            {item}
                            </li>  */}
                        </div>
                            )
                        })
                    }
import React, {Component} from 'react'
class TodoItem extends Component {
    render() {
        return <div>{this.props.content}</div>
    }
}
export default TodoItem

子组件向父组件传递数据

子组件通过this.props接收
父组件的方法要进行一次绑定

代码

import React,{ Component,Fragment } from 'react';
import './style.css'
import './TodoItem'
import TodoItem from './TodoItem';
class ToDoList extends Component {
    constructor(props) {
        super(props);
        this.state = {
            inputValue: '',
            list: []
        }
    }
    render() {
        return (
            <Fragment>
                <div>
                    <label htmlFor='insertArea' >输入内容</label>
                    <input 
                    id='insertArea'
                    className='input'
                    value={this.state.inputValue}
                    onChange={this.hanleInputChange.bind(this)}
                    />
                    <button onClick={this.hanleBtnClick.bind(this)}>提交</button>  
                </div>
                <ul> 
                    {
                        this.state.list.map((item, index) => {
                            return ( 
                            <div>
                            <TodoItem 
                            content={item}
                            index={index}
                            deleteItem={this.handleItemDelete.bind(this)}
                             />

                            { /*
                            父组件通过deleteItem方法把自己的方法传给子组件 
                            <li 
                            key = {index}
                            onClick={this.handleItemDelete.bind(this, index)}
                            dangerouslySetInnerHTML={{__html: item}}>       
                            {item}
                            </li>  */}
                          </div>
                            )
                        })
                    }
                </ul>
            </Fragment>
        )
    }
    hanleInputChange(e) {
        this.setState({
            inputValue:e.target.value
        })
    }
    hanleBtnClick() {
        this.setState({
            list:[...this.state.list, this.state.inputValue],
            inputValue: ''
        })
    }
    handleItemDelete(index) {
        console.log(index);
        //immutable概念
        //state 不允许我们做任何改变 所以拷贝修改副本
        // list.state.list.splice(index, 1) 这样子的写法是不行的 
        const list = [...this.state.list] //是一份拷贝
        list.splice(index, 1)
        //react 改变数据要求调用setState
        this.setState({
            list: list 
        })
    }
}
export default ToDoList;
import React, {Component} from 'react'
class TodoItem extends Component {
    constructor(props) {
        super(props)
        this.handleclick=this.handleclick.bind(this)
    }
    render() {
        return (
        <div 
        onClick={this.handleclick}>
            {this.props.content}
        </div>)
    }
    handleclick() {
        this.props.deleteItem(this.props.index)
    {/*调用父组件传过来的deleteitem方法 顺便把index以参数的方式传回去 */}
    }
}
export default TodoItem

代码优化

import React,{ Component,Fragment } from 'react';
import './style.css'
import TodoItem from './TodoItem';
class ToDoList extends Component {
    constructor(props) {
        super(props);
        this.state = {
            inputValue: '',
            list: []
        }
        this.hanleInputChange = this.hanleInputChange.bind(this)
        this.hanleBtnClick = this.hanleBtnClick.bind(this)
        this.handleItemDelete = this.handleItemDelete.bind(this)
    }
    render() {
        return (
            <Fragment>
                <div>
                    <label htmlFor='insertArea' >输入内容</label>
                    <input 
                    id='insertArea'
                    className='input'
                    value={this.state.inputValue}
                    onChange={this.hanleInputChange.bind(this)}
                    />
                    <button onClick={this.hanleBtnClick.bind(this)}>提交</button>  
                </div>
                <ul> 
                    {this.getTodoItem()}
                </ul>
            </Fragment>
        )
    }
    getTodoItem() {
       return  this.state.list.map((item, index) => {
            return ( 
            <div>
                {
                //如果有key值 放在循环的最外层
                }
            <TodoItem 
            content={item}
            index={index}
            deleteItem={this.handleItemDelete.bind(this)}
             />
          </div>
            )
        })
    }
    hanleInputChange(e) {
        const value = e.target.value
        this.setState(() => ({
            inputValue:value
        }))
        // this.setState({
        //     inputValue:e.target.value
        // })
    }
    hanleBtnClick() {
        // prevState是代码上一个状态的state
        this.setState((prevState) => ({
            list:[...prevState.list, prevState.inputValue],
            inputValue: ''
        }))
        // this.setState({
        //     list:[...this.state.list, this.state.inputValue],
        //     inputValue: ''
        // })
    }
    handleItemDelete(index) {
        
        this.setState((prevState) => {
            const list = [...prevState.list] 
            list.splice(index, 1)
            return {list}
        })
        // const list = [...this.state.list] 
        // list.splice(index, 1)
        // this.setState({
        //     list: list 
        // })
    }
}
export default ToDoList;
import React, {Component} from 'react'
class TodoItem extends Component {
    constructor(props) {
        super(props)
        this.handleclick=this.handleclick.bind(this)
    }
    render() {
        const { content } =  this.props 
        return (
        <div 
        onClick={this.handleclick}>
            {content}
        </div>
        )
    }
    handleclick() {
        const { deleteItem, index } = this.props
        deleteItem(index)
    {/*调用父组件传过来的deleteitem方法 顺便把index以参数的方式传回去 */}
    }
}
export default TodoItem

围绕react衍生出的思考

1.命令式编程:直接操作dom jq、原生
声名式开发:面向数据编程,节约大量dom操作的代码
2.写react可以与其他框架并存

react只负责id=‘root’的部分 不影响外部
3.组件化
父子组件通信 父组件向子组件传值 子组件调用父组件传递的方法
4.单向数据流
父组件可以向子组件传值,子组件不能直接修改父组件的值
栗子:如果一个父组件有五个子组件如果数据出现错误 定位找错的时候就比较复杂
5.视图层框架
解决数据和页面渲染的问题
大型项目处理数据传值比较复杂

6.函数式编程

1.维护容易,函数比较大的时候函数可以拆分
2.面向测试便捷性

react高级内容

安装react开发调试工具

PropTypes 与 DefaultProps

https://reactjs.org/docs/typechecking-with-proptypes.html

props,state与render函数的关系

当组件的state或者props发生改变的时候,render函数就会重新执行

当父组件的render函数被运行时,它的子组件的render都将被重新运行

react中的虚拟dom(理解还不够后期再补)

1.state数据
2.jsx模板
3.数据 + 模板 结合,生成真实的dom,来显示
4.state 发生改变
5.数据 + 模板 结合,生成真实的dom,替换原始的dom
缺陷:
第一次生成了一个完整的dom片段
第二次生成了二个完整的dom片段
第二次的dom替换第一次的dom,非常耗性能
1.state数据
2.jsx模板
3.数据 + 模板 结合,生成真实的dom,来显示
4.state 发生改变
5.数据 + 模板 结合,生成真实的dom,并不直接替换原始的dom
6.新的dom(DocumentFragment)和原始的dom做比对,找差异
7.找出input框发生了变化
8.只用新的dom中input元素,替换掉老的dom中的input元素
缺陷:
性能的提升并不明显
1.state数据
2.jsx模板
3.数据 + 模板 结合,生成真实的dom,来显示

hello world
4.生成虚拟dom(虚拟dom就是一个js对象,用它来描述真实dom) ['div',{id:'abc'},{span,{},'hello world'}] 5.state 发生变化 6.生成新的虚拟dom(虚拟dom就是一个js对象,用它来描述真实dom) ['div',{id:'abc'},{span,{},'bye'}] 7.比较原始虚拟dom和新的虚拟dom的区别 8.直接操作dom改变span中的内容

ref

ref是帮助我们在react中直接获取DOM用的
ref={(input) => {this.input=input}}

生命周期

在某一个时刻组件会自动调用执行的函数
https://juejin.cn/post/6844903842430074893
通过生命周期提高组件性能

shouldComponentUpdate(nextProps,nextState){
        if (nextProps.content !== this.props.content) {
            return true
        } else {
        return false
        }
    }

用生命周期发起ajax请求
先npm install axios

  componentDidMount() {
        axios.get('/api/todolist')
        .then(() =>{
            alert('success')
        })
        .catch(() => {
            alert('error')
        })
    }

使用Charles实现本地数据mock

http://localhost.charlesproxy.com:3000/
Charles Map Local失效解决办法,解决axios请求报404问题(完整步骤)
https://blog.csdn.net/weixin_43735348/article/details/100824002

redux


把数据都存储在公共的存储区store中,组件中尽量少放数据,当绿色组件需要改变数据时就改变store中的数据,store中一旦变化了,灰色数据会重新读取store中的数据。
Redux = Reducer + Flux

Redux 是目前 React 生态中,最好的数据层框架。Redux 是一个用来管理管理数据状态和 UI 状态的 javascript 应用工具。

通过借书的状态抽象的表示这个过程

使用antd实现todoList


todolist.js

import React, { Component } from 'react'
import 'antd/dist/antd.css'
import { List, Input, Button } from 'antd'
import store from './store'


class TodoList extends Component {
	constructor(props) {
		super(props)
		this.state = store.getState()
		this.handleInputChange = this.handleInputChange.bind(this)
		this.handleStoreChange = this.handleStoreChange.bind(this)
		store.subscribe(this.handleStoreChange)
	}
	render() {
		return (
			<div style={{ marginTop: '10px', marginLeft: '10px' }}>
				<div>
					<Input value={this.state.inputValue} placeholder="todo info" 
					style={{ width: '300px' }} 
					onChange={this.handleInputChange}
					/>
					<Button type="primary" onClick={this.handleBtnClick}>提交</Button>
				</div>
				<List
					style={{ marginTop: '10px', width: '300px' }}
					bordered
					dataSource={this.state.list}
					renderItem={(item, index) => <List.Item onClick={this.handleItemDelete.bind(this, index)}>{item}</List.Item>}
				/>
			</div>
		)
	}
	handleInputChange(e) {
		const action = {
			type: 'change_input_value',
			value: e.target.value
		}
		store.dispatch(action)
	}

	handleStoreChange() {
		this.setState(store.getState())
	}

	handleBtnClick() {
		const action = {
			type: 'add_todo_item'
		}
		store.dispatch(action)
	}

	handleItemDelete(index) {
		const action = {
			type: 'delete_todo_item',
			index
		}
		store.dispatch(action)
	}

}
export default TodoList

reducer.js

const defaultState = {
    inputValue:"hello",
    list :[1, 2]
}
// reducer 可以接受state, 但是绝对不能修改state
export default (state = defaultState, action) =>{
    if (action.type === 'change_input_value') {
        const newState = JSON.parse(JSON.stringify(state))
        newState.inputValue = action.value
        return newState
    }
    if (action.type === 'add_todo_item') {
        const newState = JSON.parse(JSON.stringify(state))
        newState.list.push(newState.inputValue)
        newState.inputValue = ''
        return newState
    }
    if (action.type === 'delete_todo_item') {
        const newState = JSON.parse(JSON.stringify(state))
        newState.list.splice(action.index, 1)
        return newState
    }
    return state
}

源码地址
https://gitee.com/thinkerwing/study/tree/master/react_study
评论私信可以分享视频链接。

以上是关于笔记react 学习与记录的主要内容,如果未能解决你的问题,请参考以下文章

学习笔记:python3,代码片段(2017)

react-router 学习笔记

React学习笔记1

react学习笔记-06

react-router 学习笔记

react 属性与状态 学习笔记