React

一、React简介

1.是什么?

React_第1张图片

  1. 发送请求获取数据
  2. 处理数据(过滤整理格式等)
  3. 操作DOM呈现页面

react是一个将数据渲染为HTML视图的开源JavaScript库。

2.为什么要学React?

1.原生JavaScript操作DOM繁琐、效率低( DOM-API操作UI)。
2.使用JavaScript直接操作DOM,浏览器会进行大量的重绘重排
3.原生JavaScript没有组件化编码方案,代码复用率低。

3.React的特点

  1. 采用组件化模式、声明式编码,提高开发效率及组件复用率。
  2. 在React Native中可以使用React语法进行移动端开发
  3. 使用虚拟DOM+优秀的Diffing算法,尽量减少与真实DOM的交互。
    原生js实现数据变动
    React_第2张图片
    React实现:
    React_第3张图片

二、React入门

1. HelloWord

<!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>
  <!-- 引入react核心库 -->
  <script type="text/javascript" src="../js/react.development.js"></script>
  <!-- 引入react-dom,用于支持react操作DOM -->
  <script type="text/javascript" src="../js/react-dom.development.js"></script>
  <!-- 引入babel,用于将jsx转为js -->
  <script type="text/javascript" src="../js/babel.min.js"></script>
  <body>
    <!-- 准备好一个容器 -->
    <div id="test"></div>
  </body>

  <script type="text/babel">
    /* 此处一定要写babel */
    //1.创建虚拟DOM
    const VDOM = <h1>Hello,React</h1>; /* 此处一定不要写引号,因为不是字符串 */
    //2.渲染虚拟DOM到页面
    ReactDOM.render(VDOM, document.getElementById("test"));
  </script>
</html>

2.关于虚拟DOM:

  1. 本质是Object类型的对象(一般对象)
  2. 虚拟DOM比较“轻”,真实DOM比较“重”,因为虚拟DOM是React内部在用,无需真实DOM上那么多的属性。
  3. 虚拟DOM最终会被React转化为真实DOM,呈现在页面上。

3.jsx语法规则:

  1.定义虚拟DOM时,不要写引号。
  2.标签中混入JS表达式时要用{}3.样式的类名指定不要用class,要用className。
  4.内联样式,要用style={{key:value}}的形式去写。
  5.只有一个根标签 (用div包起来)
  6.标签必须闭合
  7.标签首字母
       (1).若小写字母开头,则将该标签转为html中同名元素,若html中无该标签对应的同名元素,则报错。
       (2).若大写字母开头,react就去渲染对应的组件,若组件没有定义,则报错。

jsx语法规则小Demo

	<style>
		.title{
			background-color: orange;
			width: 200px;
		}
	</style>
  </head>
  <body>
    <!-- 准备好一个“容器” -->
    <div id="test"></div>

    <script type="text/babel">
      /* 此处一定要写babel */
      const myId = 'wjy'
      const myData = 'Hello,React'
      //1.创建虚拟DOM
      const VDON = (
        <h2 style={{color:"red"}} className='title' id={myId.toUpperCase()}>
          <span>{myData}</span>
        </h2>
      );
      //2.渲染虚拟DOM到页面
      ReactDOM.render(VDON, document.getElementById("test"));
    </script>

4.模块/组件

模块
  1. 理解:向外提供特定功能的js程序, 一般就是一个js文件
  2. 为什么要拆成模块:随着业务逻辑增加,代码越来越多且复杂。
  3. 作用:复用js, 简化js的编写, 提高js运行效率
组件
  1. 理解:用来实现局部功能效果的代码和资源的集合(html/css/js/image等等)
  2. 为什么要用组件: 一个界面的功能更复杂
  3. 作用:复用编码, 简化项目编码, 提高运行效率
模块化

当应用的js都以模块来编写的, 这个应用就是一个模块化的应用

组件化

当应用是以多组件的方式实现, 这个应用就是一个组件化的应用

5.React面向组件编程

函数式组件
<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	<script type="text/babel">
		//1.创建函数式组件
		function MyComponent(){
			console.log(this); //此处的this是undefined,因为babel编译后开启了严格模式
			return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2>
		}
		//2.渲染组件到页面
		ReactDOM.render(<MyComponent/>,document.getElementById('test'))
		/* 
	    执行了ReactDOM.render(.......之后,发生了什么?
		1.React解析组件标签,找到了MyComponent组件。
		2.发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中。
		*/
	</script>
</body>
类式组件:
<body>

	<div id="test"></div>

</body>
<script type="text/babel">
    //1.创建类式组件
    class MyComponent extends React.Component{
        render(){
            return <h2>我是用类定义的组件(适用于复杂组件)</h2>
        }
    }
	//2.渲染虚拟DOM到页面
	ReactDOM.render(<MyComponent/>,document.getElementById('test'))

</script>

6.组件三大核心属性

state
1.	state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)
2.	组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)

注意
this的指向问题:必须是实例调用才能指向原型,否则undefined(因为类中自动开启严格模式)

  1. 组件中render方法中的this为组件实例对象
  2. 组件自定义的方法中this为undefined,如何解决?
    a) 强制绑定this: 通过函数对象的bind()
    b) 箭头函数(推荐
  3. 状态数据,不能直接修改或更新
props
  1. 基本使用(组件内部不能修改props数据
<script type="text/babel">
		//创建组件
		class Person extends React.Component{
			render(){
				// console.log(this);
				const {name,age,sex} = this.props
				return (
					<ul>
						<li>姓名:{name}</li>
						<li>性别:{sex}</li>
						<li>年龄:{age+1}</li>
					</ul>
				)
			}
		}
		//渲染组件到页面
		ReactDOM.render(<Person name="jerry" age={19}  sex="男"/>,document.getElementById('test1'))
		ReactDOM.render(<Person name="tom" age={18} sex="女"/>,document.getElementById('test2'))

		const p = {name:'老刘',age:18,sex:'女'}
		// console.log('@',...p);
		// ReactDOM.render(,document.getElementById('test3'))
		ReactDOM.render(<Person {...p}/>,document.getElementById('test3'))
	</script>
  1. 对标签属性进行类型、必要性的限制
		static propTypes = {
			name:PropTypes.string.isRequired, //限制name必传,且为字符串
			sex:PropTypes.string,//限制sex为字符串
			age:PropTypes.number,//限制age为数值
			speak:PropTypes.func,//限制speak为函数
		}
		//指定默认标签属性值
		static defaultProps = {
			sex:'男',//sex默认值为男
			age:18 //age默认值为18
		}
函数式组件使用props
<script type="text/babel">
    //创建组件
    function Person (props){
        const {name,age,sex} = props
        return (
                <ul>
                    <li>姓名:{name}</li>
                    <li>性别:{sex}</li>
                    <li>年龄:{age}</li>
                </ul>
            )
    }
    Person.propTypes = {
        name:PropTypes.string.isRequired, //限制name必传,且为字符串
        sex:PropTypes.string,//限制sex为字符串
        age:PropTypes.number,//限制age为数值
    }

    //指定默认标签属性值
    Person.defaultProps = {
        sex:'男',//sex默认值为男
        age:18 //age默认值为18
    }
    //渲染组件到页面
    ReactDOM.render(<Person name="jerry"/>,document.getElementById('test1'))
</script>
refs

组件内的标签可以定义ref属性来标识自己

  1. String类型的Refs(已经过时,尽量避免使用)

    例如 "" type="text"/>"。你可以通过 this.refs.textInput 来访问 DOM 节点
    
  2. 回调形式的ref

    <input ref={(c)=>{this.input1 = c}}
    
  3. createRef创建ref容器·(专人专用推荐使用

    myRef = React.createRef() 
    <input ref={this.myRef}/>
    

7.事件处理

  1. React中的事件
(1).通过onXxx属性指定事件处理函数(注意大小写)
	a.React使用的是自定义(合成)事件, 而不是使用的原生DOM事件 —————— 为了更好的兼容性
	b.React中的事件是通过事件委托方式处理的(委托给组件最外层的元素) ————————为了的高效
(2).通过event.target得到发生事件的DOM元素对象 ——————————不要过度使用ref
  1. 包含表单的组件分类
  • 受控组件(将值保存到state中)
<script type="text/babel">
	//1.创建组件
	class Login extends React.Component{

        //初始化状态
        state = {
            username : '',
            password : ''
        }

        handleSubmit = (event)=>{
            //组织表单提交
            event.preventDefault() 
            const {username,password} = this.state
            alert(`你输入的用户名是:${username},你输入的密码是:${password}`)

        }

        saveUsername = (event)=>{
            this.setState({username : event.target.value})  //保存用户名到状态中
        }
        savePassword = (event)=>{
            this.setState({password : event.target.value})  //保存密码到状态中
        }

		render(){
			console.log(this)
			return (
                <form action="http://www.atguigu.com2" onSubmit={this.handleSubmit}>
                    用户名:<input onChange={this.saveUsername}  type="text" name="username" /><br/>
                    密码:  <input onChange={this.savePassword}  type="password" name="password" />
                    <button>登陆</button>
                </form>
            )
		}
	}
	//2.渲染虚拟DOM到页面
	ReactDOM.render(<Login/>,document.getElementById('test'))
</script>
  • 非受控组件
  1. 高阶函数
高阶函数:如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数。
      1.A函数,接收的参数是一个函数,那么A就可以称之为高阶函数。
      2.A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数。
      常见的高阶函数有:Promise、setTimeout、arr.map()等等

函数的柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式。
 函数的柯里化eg:
		<script type="text/javascript" >	
			function sum(a){
				return(b)=>{
					return (c)=>{
						return a+b+c
					}
				}
			}
			const result = sum(1)(2)(3)
			console.log(result);
		</script>

8.生命周期

  1. 组件从创建到死亡它会经历一些特定的阶段。
  2. React组件中包含一系列勾子函数(生命周期回调函数), 会在特定的时刻调用。
  3. 我们在定义组件时,会在特定的生命周期回调函数中,做特定的工作。
React的生命周期钩子函数
旧版本
1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
	1.	constructor()
	2.	componentWillMount()
	3.	render()
	4.	componentDidMount() =====> 常用
							一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
2. 更新阶段: 由组件内部this.setSate()或父组件render触发
	1.	shouldComponentUpdate()
	2.	componentWillUpdate()
	3.	render() =====> 必须使用的一个
	4.	componentDidUpdate()
3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
	1.	componentWillUnmount()  =====> 常用
							 一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息

React_第4张图片

	<script type="text/babel">
	
		//创建组件
		class Count extends React.Component{

			//构造器
			constructor(props){
				console.log('Count---constructor');
				super(props)
				//初始化状态
				this.state = {count:0}
			}

			//加1按钮的回调
			add = ()=>{
				//获取原状态
				const {count} = this.state
				//更新状态
				this.setState({count:count+1})
			}

			//卸载组件按钮的回调
			death = ()=>{
				ReactDOM.unmountComponentAtNode(document.getElementById('test'))
			}

			//强制更新按钮的回调
			force = ()=>{
				this.forceUpdate()
			}

			//组件将要挂载的钩子
			componentWillMount(){
				console.log('Count---componentWillMount');
			}

			//组件挂载完毕的钩子
			componentDidMount(){
				console.log('Count---componentDidMount');
			}

			//组件将要卸载的钩子
			componentWillUnmount(){
				console.log('Count---componentWillUnmount');
			}

			//控制组件更新的“阀门”
			shouldComponentUpdate(){
				console.log('Count---shouldComponentUpdate');
				return true
			}

			//组件将要更新的钩子
			componentWillUpdate(){
				console.log('Count---componentWillUpdate');
			}

			//组件更新完毕的钩子
			componentDidUpdate(){
				console.log('Count---componentDidUpdate');
			}

			render(){
				console.log('Count---render');
				const {count} = this.state
				return(
					<div>
						<h2>当前求和为:{count}</h2>
						<button onClick={this.add}>点我+1</button>
						<button onClick={this.death}>卸载组件</button>
						<button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
					</div>
				)
			}
		}
		
		//父组件A
		class A extends React.Component{
			//初始化状态
			state = {carName:'奔驰'}

			changeCar = ()=>{
				this.setState({carName:'奥拓'})
			}

			render(){
				return(
					<div>
						<div>我是A组件</div>
						<button onClick={this.changeCar}>换车</button>
						<B carName={this.state.carName}/>
					</div>
				)
			}
		}
		
		//子组件B
		class B extends React.Component{
			//组件将要接收新的props的钩子
			componentWillReceiveProps(props){
				console.log('B---componentWillReceiveProps',props);
			}

			//控制组件更新的“阀门”
			shouldComponentUpdate(){
				console.log('B---shouldComponentUpdate');
				return true
			}
			//组件将要更新的钩子
			componentWillUpdate(){
				console.log('B---componentWillUpdate');
			}

			//组件更新完毕的钩子
			componentDidUpdate(){
				console.log('B---componentDidUpdate');
			}

			render(){
				console.log('B---render');
				return(
					<div>我是B组件,接收到的车是:{this.props.carName}</div>
				)
			}
		}
		
		//渲染组件
		ReactDOM.render(<Count/>,document.getElementById('test'))
	</script>

新版本
1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
	1.constructor()
	2.getDerivedStateFromProps 
	3.render()
	4.componentDidMount()
2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发
	1.getDerivedStateFromProps
	2.shouldComponentUpdate()
	3.render()
	4.getSnapshotBeforeUpdate
3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
    1.componentWillUnmount()

React_第5张图片

重要的勾子
1.render:初始化渲染或更新渲染调用
2.componentDidMount:开启监听, 发送ajax请求
3.componentWillUnmount:做一些收尾工作,: 清理定时器

9.虚拟DOM与DOM Diffing算法

1.react/vue中的key有什么作用?(key的内部原理是什么?)
2.为什么遍历列表时,key最好不要用index?

  1. 虚拟DOM中key的作用:
1). 简单的说: key是虚拟DOM对象的标识, 在更新显示时key起着极其重要的作用。

2). 详细的说: 当状态中的数据发生变化时,react会根据【新数据】生成【新的虚拟DOM, 
							随后React进行【新虚拟DOM】与【旧虚拟DOM】的diff比较,比较规则如下:

			a. 旧虚拟DOM中找到了与新虚拟DOM相同的key:
						(1).若虚拟DOM中内容没变, 直接使用之前的真实DOM
						(2).若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM

			b. 旧虚拟DOM中未找到与新虚拟DOM相同的key
						根据数据创建新的真实DOM,随后渲染到到页面
  1. 用index作为key可能会引发的问题:
1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:
				会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。

2. 如果结构中还包含输入类的DOM:
				会产生错误DOM更新 ==> 界面有问题。
				
3. 注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,
	仅用于渲染列表用于展示,使用index作为key是没有问题的。
  1. 开发中如何选择key?:
1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
2.如果确定只是简单的展示数据,用index也是可以的。

三、React应用(基于React脚手架)

1.xxx脚手架: 用来帮助程序员快速创建一个基于xxx库的模板项目

  1. 包含了所有需要的配置(语法检查、jsx编译、devServer…)
  2. 下载好了所有相关的依赖
  3. 可以直接运行一个简单效果

2.react提供了一个用于创建react项目的脚手架库: create-react-app
3.项目的整体技术架构为: react + webpack + es6 + eslint
4.使用脚手架开发的项目的特点: 模块化, 组件化, 工程化

1.创建项目并启动

(1全局安装:npm i -g create-react-app
(2)切换到想创项目的目录,使用命令:create-react-app XXXXX
(3)第三步,进入项目文件夹:cd hello-react
(4) 第四步,启动项目:npm start/yarn start

2.react脚手架项目结构

public ---- 静态资源文件夹

rfavicon.icon ------ 网站页签图标
index.html -------- 主页面
logo192.png ------- logo图
logo512.png ------- logo图
manifest.json ----- 应用加壳的配置文件
obots.txt -------- 爬虫协议文件

src ---- 源码文件夹

App.css -------- App组件的样式
App.js --------- App组件
App.test.js ---- 用于给App做测试
index.css ------ 样式
index.js ------- 入口文件
logo.svg ------- logo图
reportWebVitals.js
— 页面性能分析文件(需要web-vitals库的支持)
setupTests.js
---- 组件单元测试的文件(需要jest-dom库的支持)

3. 样式的模块化

React_第6张图片

一般不用,用less编写一般不会冲突
安装:ES7 React/Redux/GraphQL/React-Native snippets

4. 功能界面的组件化编码流程(通用)

  1. 拆分组件: 拆分界面,抽取组件
  2. 实现静态组件: 使用组件实现静态页面效果
  3. 实现动态组件
    • 动态显示初始化数据
      • 数据类型
      • 数据名称
      • 保存在哪个组件?
    • 交互(从绑定事件监听开始)

todoList案例相关知识点

	1.拆分组件、实现静态组件,注意:className、style的写法
	2.动态初始化列表,如何确定将数据放在哪个组件的state中?
				——某个组件使用:放在其自身的state中
				——某些组件使用:放在他们共同的父组件state中(官方称此操作为:状态提升)
	3.关于父子之间通信:
			1.【父组件】给【子组件】传递数据:通过props传递
			2.【子组件】给【父组件】传递数据:通过props传递,要求父提前给子传递一个函数
	4.注意defaultChecked 和 checked的区别,类似的还有:defaultValue 和 value
	5.状态在哪里,操作状态的方法就在哪里

四、React ajax

1. 前置说明

  1. React本身只关注于界面, 并不包含发送ajax请求的代码
  2. 前端应用需要通过ajax请求与后台进行交互(json数据)
  3. react应用中需要集成第三方ajax库(或自己封装)

2. 常用的ajax请求库

  1. jQuery: 比较重, 如果需要另外引入不建议使用
  2. axios: 轻量级, 建议使用
    • 封装XmlHttpRequest对象的ajax
    • promise风格
    • 可以用在浏览器端和node服务器端

3.axios文档

五、react脚手架配置代理总结

方法一

在package.json中追加如下配置

"proxy":"http://localhost:5000"

说明:

  1. 优点:配置简单,前端请求资源时可以不加任何前缀。
  2. 缺点:不能配置多个代理。
  3. 工作方式:上述方式配置代理,当请求了3000不存在的资源时,那么该请求会转发给5000 (优先匹配前端资源)

方法二

  1. 第一步:创建代理配置文件

    在src下创建配置文件:src/setupProxy.js
    
  2. 编写setupProxy.js配置具体代理规则:

    const proxy = require('http-proxy-middleware')
    
    module.exports = function(app) {
      app.use(
        proxy('/api1', {  //api1是需要转发的请求(所有带有/api1前缀的请求都会转发给5000)
          target: 'http://localhost:5000', //配置转发目标地址(能返回数据的服务器地址)
          changeOrigin: true, //控制服务器接收到的请求头中host字段的值
          /*
          	changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
          	changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:3000
          	changeOrigin默认值为false,但我们一般将changeOrigin值设为true
          */
          pathRewrite: {'^/api1': ''} //去除请求前缀,保证交给后台服务器的是正常请求地址(必须配置)
        }),
        proxy('/api2', { 
          target: 'http://localhost:5001',
          changeOrigin: true,
          pathRewrite: {'^/api2': ''}
        })
      )
    }
    

说明:

  1. 优点:可以配置多个代理,可以灵活的控制请求是否走代理。
  2. 缺点:配置繁琐,前端请求资源时必须加前缀。

六、消息订阅-发布机制

  1. 工具库: PubSubJS
  2. 下载: npm install pubsub-js --save
  3. 使用:
    — 1)import PubSub from ‘pubsub-js’ //引入
    — 2)PubSub.subscribe(‘delete’, function(data){ }); //订阅
    — 3)PubSub.publish(‘delete’, data) //发布消息

七、扩展:Fetch

特点

  1. fetch: 原生函数,不再使用XmlHttpRequest对象提交ajax请求
  2. 老版本浏览器可能不支持

github搜索案例相关知识点

	1.设计状态时要考虑全面,例如带有网络请求的组件,要考虑请求失败怎么办。
	2.ES6小知识点:解构赋值+重命名
				let obj = {a:{b:1}}
				const {a} = obj; //传统解构赋值
				const {a:{b}} = obj; //连续解构赋值
				const {a:{b:value}} = obj; //连续解构赋值+重命名
	3.消息订阅与发布机制
				1.先订阅,再发布(理解:有一种隔空对话的感觉)
				2.适用于任意组件间通信
				3.要在组件的componentWillUnmount中取消订阅
	4.fetch发送请求(关注分离的设计思想)
				try {
					const response= await fetch(`/api1/search/users2?q=${keyWord}`)
					const data = await response.json()
					console.log(data);
				} catch (error) {
					console.log('请求出错',error);
				}

八、 关于的路由笔记

九、redux

1.redux理解

  1. 学习文档
    • 英文文档
    • 中文文档
    • Github
  2. redux是什么
    1. redux是一个专门用于做状态管理的JS库(不是react插件库)。
    2. 它可以用在react, angular, vue等项目中, 但基本与react配合使用。
    3. 作用: 集中式管理react应用中多个组件共享的状态。
  3. 什么情况下需要使用redux
    1. 某个组件的状态,需要让其他组件可以随时拿到(共享)。
    2. 一个组件需要改变另一个组件的状态(通信)。
    3. 总体原则:能不用就不用, 如果不用比较吃力才考虑使用。
  4. redux工作流程
    React_第7张图片

2. redux的三个核心概念

  1. action
    1.	动作的对象
    2.	包含2个属性
    

 type:标识属性, 值为字符串, 唯一, 必要属性
 data:数据属性, 值类型任意, 可选属性
3. 例子:{ type: ‘ADD_STUDENT’,data:{name: ‘tom’,age:18} }
2. reducer

  1. 用于初始化状态、加工状态。
  2. 加工时,根据旧的state和action, 产生新的state的纯函数。
  3. store
    1.	将state、action、reducer联系在一起的对象
    2.	如何得到此对象?
        1)	import {createStore} from 'redux'
        2)	import reducer from './reducers'
        3)	const store = createStore(reducer)
    3.	此对象的功能?
        1)	getState(): 得到state
        2)	dispatch(action): 分发action, 触发reducer调用, 产生新的state
        3)	subscribe(listener): 注册监听, 当产生了新的state时, 自动调用
    

3.redux的核心API

  1. createstore()
    作用:创建包含指定reducer的store对象
  2. store对象
  • 作用: redux库最核心的管理对象
  • 它内部维护着:

    state
    reducer

  1. 核心方法:
        >	getState()
        >	dispatch(action)
        >	subscribe(listener)
    
  2. 具体编码:
    store.getState()
    store.dispatch({type:'INCREMENT', number})
        store.subscribe(render)
    
  3. applyMiddleware()
    作用:应用上基于redux的中间件(插件库)
  4. combineReducers()
    作用:合并多个reducer函数

1.求和案例_redux精简版

(1).去除Count组件自身的状态
(2).src下建立:
                -redux
                    -store.js
                    -count_reducer.js

(3).store.js:
            1).引入redux中的createStore函数,创建一个store
            2).createStore调用时要传入一个为其服务的reducer
            3).记得暴露store对象

(4).count_reducer.js:
            1).reducer的本质是一个函数,接收:preState,action,返回加工后的状态
            2).reducer有两个作用:初始化状态,加工状态
            3).reducer被第一次调用时,是store自动触发的,
                            传递的preState是undefined,
                            传递的action是:{type:'@@REDUX/INIT_a.2.b.4}

(5).在index.js中监测store中状态的改变,一旦发生改变重新渲染<App/>
        备注:redux只负责管理状态,至于状态的改变驱动着页面的展示,要靠我们自己写。

2.求和案例_redux完整版

新增文件:
    1.count_action.js 专门用于创建action对象
    2.constant.js 放置容易写错的type值

3.求和案例_redux异步action版

(1).明确:延迟的动作不想交给组件自身,想交给action
(2).何时需要异步action:想要对状态进行操作,但是具体的数据靠异步任务返回。
(3).具体编码:
        1).yarn add redux-thunk,并配置在store中
        2).创建action的函数不再返回一般对象,而是一个函数,该函数中写异步任务。
        3).异步任务有结果后,分发一个同步的action去真正操作数据。
(4).备注:异步action不是必须要写的,完全可以自己等待异步任务的结果了再去分发同步action。

4.求和案例_react-redux基本使用

(1).明确两个概念:
            1).UI组件:不能使用任何redux的api,只负责页面的呈现、交互等。
            2).容器组件:负责和redux通信,将结果交给UI组件。
(2).如何创建一个容器组件————靠react-redux 的 connect函数
                connect(mapStateToProps,mapDispatchToProps)(UI组件)
                    -mapStateToProps:映射状态,返回值是一个对象
                    -mapDispatchToProps:映射操作状态的方法,返回值是一个对象
(3).备注1:容器组件中的store是靠props传进去的,而不是在容器组件中直接引入
(4).备注2:mapDispatchToProps,也可以是一个对象

5.求和案例_react-redux优化

(1).容器组件和UI组件整合一个文件
(2).无需自己给容器组件传递store,给<App/>包裹一个<Provider store={store}>即可。
(3).使用了react-redux后也不用再自己检测redux中状态的改变了,容器组件可以自动完成这个工作。
(4).mapDispatchToProps也可以简单的写成一个对象
(5).一个组件要和redux“打交道”要经过哪几步?
        (1).定义好UI组件---不暴露
        (2).引入connect生成一个容器组件,并暴露,写法如下:
                connect(
                    state => ({key:value}), //映射状态
                    {key:xxxxxAction} //映射操作状态的方法
                )(UI组件)
        (4).UI组件中通过this.props.xxxxxxx读取和操作状态

6.求和案例_react-redux数据共享版

(1).定义一个Pserson组件,和Count组件通过redux共享数据。
(2).为Person组件编写:reducer、action,配置constant常量。
(3).重点:Person的reducer和Count的Reducer要使用combineReducers进行合并,
        合并后的总状态是一个对象!!!
(4).交给store的是总reducer,最后注意在组件中取出状态的时候,记得“取到位”。

7.求和案例_react-redux开发者工具的使用

(1).yarn add redux-devtools-extension
(2).store中进行配置
        import {composeWithDevTools} from 'redux-devtools-extension'
        const store = createStore(allReducer,composeWithDevTools(applyMiddleware(thunk)))

8.求和案例_react-redux最终版

(1).所有变量名字要规范,尽量触发对象的简写形式。
(2).reducers文件夹中,编写index.js专门用于汇总并暴露所有的reducer

9. react-redux使用hooks替代connect

十.react-拓展

umi

官网
umi的connect用法

你可能感兴趣的:(rea)