2022/4/8

antd:
ReactDom.render(标签,节点)
render() { return 标签 }
标签复用。

学会怎么复用组件,看官方这样写:

const data = [
  'Racing car sprays burning fuel into crowd.',
  'Japanese princess to wed commoner.',
  'Australian walks 100km after outback crash.',
  'Man charged over missing wedding girl.',
  'Los Angeles battles huge wildfires.',
];

ReactDOM.render(
  <>
    <Divider orientation="left">Default Size</Divider>
    <List
      header={<div>Header</div>}
      footer={<div>Footer</div>}
      bordered
      dataSource={data}
      renderItem={item => (
        <List.Item>
          <Typography.Text mark>[ITEM]</Typography.Text> {item}
        </List.Item>
      )}
    />
    <Divider orientation="left">Small Size</Divider>

然后自己转换:

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


const data = [
  'Racing car sprays burning fuel into crowd.',
  'Japanese princess to wed commoner.',
  'Australian walks 100km after outback crash.',
  'Man charged over missing wedding girl.',
  'Los Angeles battles huge wildfires.',
];

class TodoList extends Component {

	render() {
		return (
			<div style={{marginTop: '10px', marginLeft: '10px'}}>
				<div>
					<Input placeholder='todo info' style={{width: '300px', marginRight: '10px'}}/>
					<Button type="primary">提交</Button>
				</div>
				<List
					style={{marginTop: '10px', width: '300px'}}
		      bordered
		      dataSource={data}
		      renderItem={item => (<List.Item>{item}</List.Item>)}
		    />
			</div>
		)
	}

}

export default TodoList;

以render()为界,可以知道数据应该被写在哪里。比如data数据,比如< list> 标签。

js垃圾回收机制:https://cloud.tencent.com/developer/article/1852932
(标记清除和引用计数,之前学过,再学一遍)

实际例子:
通过input输入框enter键实现动态添加列表数据:onKeyPress={this.handleEnterKey}
(这段代码是自己敲的,把原先antd官网的data数据变成了list,存在state里,这样才能保证数据更新,页面刷新。
如果像antd官网那样设置data数据,那么即使data发生了变化页面也不会刷新,就不好用了)

react:
import React, { Component } from 'react';
import 'antd/dist/antd.css';
import { Input , Button ,List} from 'antd';
class TodoList extends Component {
	constructor(props){
		super(props);
		this.state={
			inputValue:"",
			list:[
				'Racing car sprays burning fuel into crowd.',
				'Japanese princess to wed commoner.',
				'Australian walks 100km after outback crash.',
				'Man charged over missing wedding girl.',
				'Los Angeles battles huge wildfires.',
			  ]
		}
        this.handleClick = this.handleClick.bind(this);
		this.handleInputChange = this.handleInputChange.bind(this);
		this.handleEnterKey = this.handleEnterKey.bind(this);
	}
	render() {
		return (
			<div style={{marginLeft:'30px',marginTop:'20px'}}>
				<Input placeholder="hello" style={{width:'300px'}} value={this.state.inputValue} onChange={this.handleInputChange} onKeyPress={this.handleEnterKey}></Input>
				<Button type="primary" style={{marginLeft:"20px"}} onClick={this.handleClick}>提交</Button>
                <List     style={{marginTop:'20px',width:'300px'}}
                          size="small"
                          bordered
                          dataSource={this.state.list}
                          renderItem={item => <List.Item>{item}</List.Item>}
    />
			</div>
		)
	}

	handleClick(){
		this.setState(()=>({
			list:[...this.state.list,this.state.inputValue],
			inputValue:""
		}))
	
		
	}

	handleInputChange(e){
		const value = e.target.value;
		this.setState(()=>({inputValue:value})); //这里应该是{inputValue:value},之前写少了{}
	}

	//判断点击的键盘的keyCode是否为13,是就调用上面的搜索函数
    handleEnterKey = (e) => {
        if(e.nativeEvent.keyCode === 13){ //e.nativeEvent获取原生的事件对像
           this.handleClick()
    }
}

}

export default TodoList;

vue:
在vue中则是: @keyup.enter.native="handleClick" ,
vue不像react,还需要借助handleEnterKey去判断键盘数,才能触发handleClick.

react:onKeyPress={this.handleEnterKey} vue:@keyup.enter.native="handleClick" 

5-1 开始学redux
Redux = Reducer+Flux

store就像一个公用的父组件,在这个父组件里,有属性,有接口。就像一个库。
(关于store和reducer关系请移步2022/4/8 redux )
第一步:yarn add redux
第二步:创建store,通过redux的createStore方法
第三步:创建笔记本,并导入store,笔记本是个函数,接收两个参数:state,action
所以,store/index.js中代码:

import { createStore } from 'redux';
import reducer from './reducer';

const store = createStore(reducer);

export default store;

store/reducer.js代码:

const defaultState = {
	inputValue: '123',
	list: [1, 2]
}

export default (state = defaultState, action) => {
	return state;
}

(注意:reducer只是个取名方式罢了,归根结底还是因为createStore()需要接收一个函数,函数里面的参数是state和action罢了)

store的使用:createStore((state,action)=>{ return state } )
通过store.getState()可以获取state数据

根据如上的store文件可以在下面使用相关代码:
在constructor里:
this.state = store.getState(); this.state是个对象。
在render()里。
<list dataSource = { this.state.list}

5-5 Action 和 Reducer 的编写

首先,需要先在chrome浏览器下载redux插件。(redux devtools)
安装完后,需要在createStore增加window.REDUX_DEVTOOLS_EXTENSION && window.REDUX_DEVTOOLS_EXTENSION()
store/index.js代码如下:

import { createStore } from 'redux';
import reducer from './reducer';

const store = createStore(
	reducer, 
	window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);

export default store;

关于改变store里的数据(之前获取数据是 通过store.getState())
组件改变store的数据需要用到:action

组件代码:
在组件对应的触发事件里写:action , action 是个对象, type中注明该action要做什么事。

handleInputChange(e) {
   const action = {
      type:'change_input_value',
      value:e.target.value 
  }
  store.dispatch(action)
}

通过store.dispatch(action),组件将这句话传给store.

Store代码:需要将当前的state和action一并传给手册Reducers(Reducers是函数,来源于createStore)
这个部分由store自动执行,因此开发者不需要敲代码,在Reducer里可以自然接收到当前的state和action

发现了吗,reducer是个函数,接收的不管是state,还是action,都是对象。那么就看怎么通过action对state进行操作吧。
还记得reducer这个函数返回的是state吗?按照这个逻辑,reducer怎么修改数据的思路已经浮于纸上了。

reducer.js关键代码如下:
// 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;
	}
	return state;
}

reducer返回的newState给了store,返回数据后store就会自动替代掉之前的state数据。
而组件获取数据,就像之前的store.getState()一样。

可以知道,store自动做了两件事,一是把store和action交给reducer做,二是将store的数据替换成reducer函数返回的newState

组件如上写完了,store的reducer也写好了,这时候当组件修改数据的时候,会触发action的都将修改store的数据。
可是,因为this.state = store.getState(),state无法根据store的数据进行实时变化,因此
要在constructor里加这句话:store.subscribe(this.handleStoreChange) (记得在这之前先绑定handleStoreChange)
代码如下:

class TodoList extends Component {

	constructor(props) {
		super(props);
		this.state = store.getState();
		this.handleInputChange = this.handleInputChange.bind(this);
		this.handleStoreChange = this.handleStoreChange.bind(this);
		this.handleBtnClick = this.handleBtnClick.bind(this);
		this.handleDelete = this.handleDelete.bind(this);
		store.subscribe(this.handleStoreChange);
	}

注意:在store.subscribe()中注册的函数,它能够在store发生变化的时候被触发:
添加:
handleStoreChange() {
this.setState(store.getState());
}

store.subscribe(this.handleStoreChange): 监听store数据变化,触发某个函数自动执行。
这个this.handleStoreChange就相当于store的一个钩子了~

整个Redux就是:react组件首先要改变store里的数据,先要开发出一个action,action会通过dispatch方法传递给store,store会把之前的数据和action转发给reducer,reducer是个函数,他先接收到了state和action之后做一些处理返回一个新的state给到store,store用这个新的state替换原先的state,然后store数据发生改变的时候,react组件会感知到store发生改变,这时候它从store重新取数据,更新组件的内容,页面就跟着发生变化了。

完整的react代码如下:

首先是 组件:

import React, { Component } from 'react';
import 'antd/dist/antd.css';
import { Input, Button, List } 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);
		this.handleBtnClick = this.handleBtnClick.bind(this);
		this.handleDelete = this.handleDelete.bind(this);
		this.handleEnterKey = this.handleEnterKey.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', marginRight: '10px'}}
						onChange={this.handleInputChange}
						onKeyPress={this.handleEnterKey}
					/>
					<Button type="primary" onClick={this.handleBtnClick}>提交</Button>
				</div>
				<List
					style={{marginTop: '10px', width: '300px'}}
		      bordered
		      dataSource={this.state.list}
		      renderItem={(item,index) => (<List.Item key={index} onClick = {this.handleDelete.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);
	}

	handleDelete(index){
		console.log(index)
		const action = {
			type:'delete_todo_item',
			value:index
		};
		store.dispatch(action);

	}
	handleEnterKey(e){
		if(e.nativeEvent.keyCode === 13){
			this.handleBtnClick();
		}
	}

}

export default TodoList;

其次是store/index.js
import { createStore } from 'redux';
import reducer from './reducer';

const store = createStore(
	reducer, 
	window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);

export default store;

最后是store/reducer.js
const defaultState = {
	inputValue: '123',
	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.value,1);
		return newState;
	}

	return state;
}

代码优化:
因为总是要派发action(action是个对象,它的type是字符串)
如果有很多个action,一个action的type要用到很多地方,
为了防止被修改时要改很多地方有时会出现漏掉字符的情况,
那么就把这些actionTypes进行拆分,做为常量引入

做法,在store文件夹创建actionTypes.js文件:

export const CHANGE_INPUT_VALUE = 'change_input_value';
export const ADD_TODO_ITEM = 'add_todo_item';
export const DELETE_TODO_ITEM = 'delete_todo_item';

不管是在组件,还是在reducer.js中,都是通过:

import { CHANGE_INPUT_VALUE, ADD_TODO_ITEM, DELETE_TODO_ITEM } from './store/actionTypes'
import { CHANGE_INPUT_VALUE, ADD_TODO_ITEM, DELETE_TODO_ITEM } from './actionTypes'

引入这些变量。

然后当成原先的字符串直接用就行。

用变量而不用字符串的原因在于即使写错了,react也能找到错误,毕竟一个未声明的变量直接被拿来用是会报错的。
这大概也是为什么用常用变量名的原因吧。
变量代替字符串——便于发现bug。

reactNative:https://www.imooc.com/learn/808 (鹅鹅鹅)

5-8 使用actionCreator 统一创建action

这一节也是在对代码进行优化,就像actionType对type进行统一管理一样,actionCreator是对action进行统一管理。
在store文件夹里创建actionCreator.js文件。

actionCreator.js代码:
import { CHANGE_INPUT_VALUE, ADD_TODO_ITEM, DELETE_TODO_ITEM } from './actionTypes';

export const getInputChangeAction = (value) => ({
	type: CHANGE_INPUT_VALUE,
	value
});

export const getAddItemAction = () => ({
	type: ADD_TODO_ITEM
});

export const getDeleteItemAction = (index) => ({
	type: DELETE_TODO_ITEM,
	index
});

我们都知道,这是精简函数,返回的是()内的内容,而这里括号的内容就是对象。这个对象就是action对象。
我们要的就是action对象。
so,当使用的时候就是直接调用函数,函数会返回对象的。

handleInputChange(e) {
		const action = getInputChangeAction(e.target.value);
		store.dispatch(action);
	}

(偶尔觉得,函数老是被当成对象用hh,因为对象属性值老是在变化,才会需要函数引入,函数就像动态对象一样hhh)

(!!!函数就像一个动态对象 export const getDeleteItemAction = (index) => ({
	type: DELETE_TODO_ITEM,
	index
});)

关于action对象,第一个属性名是type,第二个属性名可以按实际情况取。
reducer是纯函数,纯函数的意思即不改变传入的参数,reducer收到的参数是state和action,
那么意思就是reducer函数即既不可以改变state,又不可以改变action。
reducer复制state,修改副本,返回数据给store,由store去替换state

纯函数除了不改变传入的参数外,还有一个特点,固定的输入和固定的输出,所以输出永远是state,不会是其它,比如false,true之类的。
所以纯函数里既不能有时间操作,也不能有请求。

Redux相关api: createStore,store.dispatch,store.getState(),store.subscribe()

虽然今天心情不好,但是第五章居然已经学完了。
我觉得自从我明白方法,接口,组件这些概念后,redux其实不过是它们的整合。
属性,接口,放后端,负责逻辑处理,前端的话,只要调用就行了。
redux又何尝不是用了后端这种思想呢,删除,添加也罢,都交给reducer去做,reducer再把数据返回给store罢了。
需知,reducer是个纯函数。
接口,之前,写过很多了,用import 引入,都是export const ,归根结底,不过是一种语法糖。
函数,返回对象,该函数,不过是个动态对象,动态改变对象的某个属性值罢了。

开始学第六章吧。

关于无状态组件:

无状态组件
当一个组件里只有一个render函数时,可以使用无状态组件去代替
无状态组件实际上就是一个函数,性能较高

性能高:普通组件是一个类,还有许多生命周期函数需要执行,而无状态组件只是一个函数
当ui组件只负责渲染,没有做复杂逻辑操作时,一般都可以通过无状态组件来定义

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值