# react-admin **Repository Path**: smarterlo/react-admin ## Basic Information - **Project Name**: react-admin - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-10-16 - **Last Updated**: 2021-09-13 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). ## Available Scripts In the project directory, you can run: ### `yarn start` Runs the app in the development mode.
Open [http://localhost:3000](http://localhost:3000) to view it in the browser. The page will reload if you make edits.
You will also see any lint errors in the console. ### `yarn test` Launches the test runner in the interactive watch mode.
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. ### `yarn build` Builds the app for production to the `build` folder.
It correctly bundles React in production mode and optimizes the build for the best performance. The build is minified and the filenames include the hashes.
Your app is ready to be deployed! # react基础知识记录点: ## jsx的语法规则 1.定义虚拟DOM时,不要写引号。
2.标签中混入js表达式要用{}。
3.样式的类名指定不要class 。要用className 因为与class 关键字重名。
4.内联样式,要用style={{key:value}}的形式去写 (注:{}是js表达式{}是json对象,所以是两层{{}})。
5.虚拟DOM必须只有一个根标签
6.标签必须闭合
7.标签首字母 (1)若小写字母开头,则将改标签转为html同名元素,若html无该标签 报错。
(2)若大写字母开头,react就去渲染对应的组件,若组件没有定义 报错。
## 函数组件(简单组件) 1.直接return jsx 语句 ## 类式组件(复杂组件) 1.必须extends React.Component 2.必须有render(){} (render是放在类的原型对象上,供实例使用) 3.render的this 是组件实例对象 是new出来的实例对象 ## ReactDOM.render(); 1.React解析组件标签,找到MyComponent组件。
2.发现组件使用函数定义,直接调用
3.发现组件使用类定义,随后new出类的实例,并通过该实例调用到原型的 render方法。将render返回的虚拟dom转化为真实dom,随后呈现页面中。
## 组件实例的三大核心属性 1.类组件实例也就是 this 下面 会有 state.props.refs三大属性
### state 状态管理,用于记录实例内的参数。
1.类的方法this指向
2.onClick = {this.func}
注:func在类的原型对象上。但是 由于func是作为onClick的回调,所以不是通过实例调用的。 是直接调用。
类中方法默认开启了局部的[严格模式],所以func中的this为undefined 所以无法直接找到this.state
3.解决this的指向:
在constructor()中 this.func = this.func.bind(this) 将类中的func的bind传入this指向。 然后赋值给右边的实例中的func 函数直接调用。
简单点就是等式左边的this.func是onClick里的表达式 用来给 实例对象挂载一个func方法。 右边的 this.func 是类的原型上的func通过bind 传入构造器的this就是实例对象本身。然后给赋值给左边
就是右边呢把原型上的this改成了实例对象的this 然后呢 在给实例挂载一个新的方法。 把原型改过了this指向的方法 赋值给 实例挂载的新方法。
最后点击onClick的方法 就是 调用的是实例自身的新的func方法了。
🐮🍺,react的this玩的🐮。套娃
4.状态无法直接更改.通过内置api setState修改 是合并 不是替换。
this.setState({})
Q:构造器调用几次? A:1一次
Q:render调用几次? A:1+n次,1次是初始化那次,n是状态更新
Q:方法调用几次? A:用几次调用几次
5.state的简写
state 可以不写在构造器。 直接给 state = {} 赋值。
自定义方法可以用赋值语句形式 箭头函数解决this指向问题 如: func = () =>{}; 不需要bind(this)
相当于吧 state 和 自定义方法 写在了自身的实例上。 原型上面就没自定义的方法。 (类用的秒啊 ! 学到了)
### props 给组件传参,用于给组件传自定义标签属性数据。 props 只读 不能去修改
1.批量传入props
如 params = {}含有多个key -value , {...params} 展开运算符来传整个params 只能用于react中组件传值 ...p 写法。 react提供的语法糖。
[回顾展开运算符知识点]:注意:原生里 不能 ...params 不能展开json对象 但是 {...params} 可以拷贝对象。
(1) 数组展开 console.log(...array)
(2) 连接数组 【...array1,...array2】
(3) 函数中使用 function fuc(...numbers){} //这里numbers 会变成一个数组。就是func接收的值 会变成一个自定义长度的数组。 列如传入 func(1,2,3), ...numbers之后就是 【1,2,3】
(4) 构造字面量对象时使用展开语法 也就是对象赋值 浅拷贝 只能第一层 如:let obj1 = {a:1}; let obj2 = {...obj1}; 可以拷贝obj1的属性。 并且不影响obj1。
(5) 合并对象 let obj1 = {a:1}; let obj2 = {...obj1,b:2,a:3}
注意: 数组合并用[] 对象用{}
2.对props标签属性的限制
```javascript Mycomponent.propTypes = { name:PropTypes.string.isRequired, // 是string 字符串还是必须的 age:PropTypes.number func:PropTypes.func // 如果传一个function 方法。 通过 func来限制 } ``` 注意:propTypes 是类组件的属性。react通过该属性识别类组件的prop要求规则。 PropTypes是react提供的一个js类型校验库。
3.对props标签属性的默认值
```javascript Mycomponent.defaultProps = { age:18 } ``` 4.props的简写
将propTypes.defaultProps 加入类的属性里 代码写在类里面 用static 静态属性
如:static propTypes = {}; static defaultProps = {}
构造器是否接收props ,是否传递super 取决于是否在构造器中用this访问props。如果构造器里不用访问this里的props 可以不用接受props 也不用super。
构造器可以不写。 写的话仅用于 this.state 赋值 及 bind(this);
开发时候基本不写构造器。能省就省。(舒服 ヾ(。`Д´。))
5.props可以用于函数式组件
```javascript function func(props){ //props 函数式组件里可以得到 } ``` 不能简写 不能用static必须函数外面 func.propTypes func.defaultProps
### refs与事件处理 ref 可以给元素标检增加唯一标识属性(类似id)
1.字符串ref='string' this.refs 里可以取到对应的key 不建议使用 效率问题。 未来可能抛弃
2.回调ref this.input1 = currentNode} /> 放在了实例对象 this 本身 这个更新时候会执行两次。第一次是null。基本没影响 如果想避免可以用类的绑定方法以下
saveDom = (c)=>{}
3.createRef React.createRef() 调用后 返回一个容器。该容器存储一个被ref所标识的节点 只能存一个。 myRef = React.createRef() this.myRef.current.value 取的input值 事件处理:(1)通过onXxx属性指定事件处理函数 a.React 使用的是自定义(合成)事件,而不是原生DOM 事件 ---为了兼容性 b.React 中事件通过事件委托方式处理(委托给组件最外层元素) ---为了高效 (2)通过event.target得到发生事件DOM元素对象 func(event){event.target} // 通过event 可以不过度使用refs ## 受控组件 : 组件值存在state 里的值 ## 非受控组件 : 直接用 没保存状态中。 ## 高阶函数 如果一个函数符合下面2个规范中的一个,那该函数就是高阶函数 1.若A函数,接收的参数就是一个函数, 2.若A函数,返回值是一个函数。 常见的高阶函数 Promise、setTimeout、arr.map() 函数柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式。 ## 组件生命周期 ### 旧的生命周期 1.初始化阶段:由ReactDOM.render()触发 ---初次渲染 (1)constructor() //构造器 (2)componentWillMount() //组件将要挂载 (3)render() //挂载渲染 (4)componentDidMonut //组件挂载完毕 ==>常用 做一些初始化 2.更新阶段:由组件内部this.setState()或父组件重新render触发 (1)shouldComponentUpdate() //是否允许被更新。 必须返回一个boolean类型 (2)componentWillUpdate() //组件将要更新 (3)render() //挂载渲染 (4)componentDidUpdate() //组件更新完毕 3.卸载组件:由组件内部ReactDOM.unmountComponentAtNod()触发 (1)componentWillUnmount() ==>常用 做一些收尾的事情 ### 新的生命周期 废了3个 新出2个 核心钩子没变化。 不碍事 1.初始化阶段:由ReactDOM.render()触发 ---初次渲染 (1)constructor() //构造器 (2)getDerivedStateFromProps() (3)render() //挂载渲染 (4)componentDidMonut //组件挂载完毕 ==>常用 做一些初始化 2.更新阶段:由组件内部this.setState()或父组件重新render触发 (1)getDerivedStateFromProps() (2)shouldComponentUpdate() //是否允许被更新。 必须返回一个boolean类型 (3)render() //挂载渲染 (4)getSnapshotBeforeUpdate() (5)componentDidUpdate() //组件更新完毕 3.卸载组件:由组件内部ReactDOM.unmountComponentAtNod()触发 (1)componentWillUnmount() ==>常用 做一些收尾的事情 ## DOM的diffing算法 ## 兄弟组件通信 ### pubsub-js 消息订阅js库 ```javascript // 创建回调 接收消息 和 数据 在 componentDidMount 里创建 var mySubscriber = function (msg, data) { console.log( msg, data ); }; //订阅消息,关联回调函数 var token = PubSub.subscribe('MY TOPIC', mySubscriber); // 发布一个消息 PubSub.publish('MY TOPIC', 'hello world!'); //取消订阅 componentWillUnmount PubSub.unsubscribe(token); ``` ## fetch 1. fetch: 原生函数,不再使用XmlHttpRequest对象提交ajax请求 2. 老版本浏览器可能不支持 ## 路由组件 1.接收到props不同 (重点) 一般组件写标签时传什么得到什么 路由组件会得到三个固定属性 history: action: "PUSH" block: ƒ block(prompt) createHref: ƒ createHref(location) go: ƒ go(n) goBack: ƒ goBack() goForward: ƒ goForward() length: 2 listen: ƒ listen(listener) push: ƒ push(path, state) replace: ƒ replace(path, state) [[Prototype]]: Object hash: "" key: "wk024q" pathname: "/about" search: "" state: undefined [[Prototype]]: Object match: isExact: true params: {} path: "/about" url: "/about" [[Prototype]]: Object location: hash: "" pathname: "/home" search: "" state: undefined [[Prototype]]: Object match: params: {} path: "/home" url: "/home" [[Prototype]]: Object 2.写法不同 一般组件 路由组件 ## switch 1.通常情况,path与component是一一对应的关系。 2.Switch可以提高路由匹配效率(单一匹配) ## 多级路劲页面样式丢失问题 1.使用%PUBLIC_URL%/来引入路径 2.使用HashRouter 3.使用/ 代替./引入 ## 路由的严格匹配和模糊匹配 1.默认使用模糊匹配 2.开地严格匹配 3.严格匹配不要随便开。 模糊匹配有问题的时候在开。 ## 向路由组件传递参数 1.params参数 路由连接(携带参数) 详情 注册路由(声明接收) 接收参数 this.props.match.parms 2.search参数 路由连接(携带参数) 详情 注册路由(无需声明,正常注册即可) 接收参数 this.props.location.search 备注:获取到的是search是urlencode编码字符串。需要借助querystring库解析 3.state参数 路由连接(携带参数) 详情 注册路由(无需声明,正常注册即可) 接收参数 this.props.location.state 备注:刷新可以保留参数 ## 编程式路由导航 this.props.history对象上的api对操作路由跳转、前进、后退 push(),replace(),goBack(),goForward(),go() ## BrowserRouter与hashRouter的区别 1.底层原理不一样: BrowserRouter 使用的是H5的history api 不兼容IE9及以下版本。 HashRouter使用的是url的哈希值 2.path表现形式不一样 BrowserRouter的路劲中没有#,例如 localhost:3000/demo/test HashRouter路劲有# 例如 localhost:3000/#/demo/test 3.对路由state参数影响 BrowserRouter没有任何影响,因为state保存在history对象里 HashRouter刷新后会导致路由state参数丢失 !!! 4.备注 HashRouter可以用于一些解决路劲错误的相关问题。 ## 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中状态的改变,一旦发生改变重新渲染 备注: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,给包裹一个即可。 (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