Free Code Camp 学习笔记
React
- React 可以使用JSX直接来写html 的code:
const JSXCODE = <h1>Hello World!</h1>如果想要在屏幕上看到这个JSXCODE的话,需要render这个react的codeReactDOM.render(JSXCODE, document.getElementById('root'));这就是把这个JSXCODE放到root里面去,root是body的根元素,所以就等于把这个<h1>的元素放到了body里面,这样就可以显示出来了。
2. 当然JSX也可以是多个元素组成的一个div,但是注意,一个JSX只能返回一个元素,可以是多重嵌套的,但是不能分开的:
false:const JSX = <p> hello world </p>
<p> some other text </p>
correct: const JSX = <div>
<p> hello world </p>
<p> some other text </p>
</div>
3. comment: {/* comment */}
4. 上文中提到,如果想让这个JSX表导出来,得把它在入道html文件中去,也就是一个render的过程: ReactDOM.render(componentToRender, targetNode)
5. 关于class:由于class是js的keyword,但是我们在写html是也会用到class property,解决方法:html中的class=》className
const JSX = (
<div className="some-class-name">
<h1> SOME TEXT </h1>
</div>
)这样就解决了class关键字冲突的问题。还有就是JSX一定要close tag: <br> => <br />; <hr> => <hr />
6. 不一定就要用JSX的方式来创建html,也可以用React的component的方式来建立:
两种方法, 1. javascript function:
const componentName = () => {
return (
<div>
<p>HTML body</p>
</div>
);
}
2. ES6 class:
class ComponentName extend React.Component {
constructor(props) {
super(props);
}
render() {
return (<div><p>HTML body</p></div>);
}
7. Component之间可以相互嵌套,但是要用< />套起来
const firstComponent=()=>{
return <div><h1>Some TEXT</h1></div>;
}class SecondComponent extends React.Component {
constructor(props){super(props);}
render() { return <div><firstComponent /></div>;}
}const thirdComponent=()=>{
return <div><h1>testing</h1><SecondComponent /></div>;
}这样写是可以的
*************************
但是在采用reactDOM来render的时候要注意,和JSX不一样,JSX直接挂变量名,而这时候要用< />套起来
*************************ReactDOM.render(<thirdComponent />, document.getElementById('target-id'));
8. Props=> properties,可以作为参数被pass到return的JSX中:
const someComponent = (props) => <div><p>{props.name}</p></div>
*****************
props 也可以是一个array
*****************那如果我们要取出array的值,我们就需要用到joinconst TestComponent = (props) => <h1>{props.varname.join(", ")</h1>const SomeComp = () => <div><TestComponent varname={["格式", "要", "记住"]};这时候,varname中的array元素就会被join起来,做成一个string,返回给这个<h1>然后在表现层表达。*******************
我们也可以给这个props一个初始值,当不设定的的时候,我们自动取这个初始值
*******************TestComponent.defaultProps = {key:value};使用的时候: <div>
<TestComponent key="new-val" />
</div>*******************
特殊情况:当我们要设定的元素是一个数字的时候,要注意,这种key=“val”的形式只能传递string,传递int需要加{}, 让react知道,这是在传递一个javascript的object,而不是string了。
*******************<div>
<TestComponent quantity={10} />
</div>
**********
propTypes: 我们可以要求传入数据的种类,这样会使系统更安全;要注意这个地方也是hash
**********TestComponent.propTypes = {quantity:PropTypes.number(/func...)
9. this.props.data: 之前我们说的都是component之前传递props,如果是class怎么传递呢?其实也很简单,只需要在props前面加一个this就可以了:
class One extends React.Component {
constructor(props) {super(props);}
render() {return <div><h1>{this.props.words}</h1></div>;}
}class Two extends React.Component {
constructor(props) {super(props);}
render() {return <div><h1>Hi, these are the words</h1><br /><One words="nothing" />;}
}
10. ********* STATE ************
state 是一个很重要的概念,就是这个component目前处于一个什么态,这个态是可以改变的。state这个元素在这个object内部是可以改变的,我不知道prop可不可以改变。class A extends React.Component {
constructor(props) {
super(props);
this.state = {key:value};
//必须是一个javascript的object
}
render() {
if (this.props.varname == "some_value") {
this.state = {key: "altered_value");
}
return <h1>{this.state.key}</h1>;
}
}这种写法是可行的,也就是说,我们可以通过传入不同的props来影响render出来的html的状态。虽让上述的写法可行,但是react还是不允许这种写法,它要求修改state的行为一定要通过一个叫做setState的函数来进行:render() {
if(this.props.varname == "some_value") {
this.setState({key: "altered_value"});
}
}这种setState的方法还是比较直接的。可以通过其他的function来完成这个setState的过程,但是略复杂,涉及到function 和 this 之间的关系class SomeComponent extends React.Component {
constructor(props) {
super(props);
this.state = {key:value};
this.funcName = this.funcName.bind(this);
//这样一来,这个function(funcName)就已经和这个component 绑定上了,否则会出现function undefined的这个情况。
}
funcName() {
this.setState({key:new_value});
}
render() {
<div>
<button onClick={this.funcName}>Submit</button>
</div>
}
}
**********************
bind(this)
**********************javascript既是oop也是functional 的,它的function是可以传递给变量的,
const aFunc = (words) => console.log(words);
const bFunc = aFunc;
bFunc("hello world");
是可以执行的。但是如果我们处理的是对象中的method,而不是这种function的话,就会出现问题,再给一个variable赋值成instance method的时候,“this”就不再是instance/object 本身了,这个可能就变成了一个当下正在处理的某个元素了,这样很容易就出现了method undefined这种情况了。dog = { name : "Paul",
bark : function(){ return `${this.name} said Whoof!`;}
}let dogBark= dog.bark;
dogBark(); => undefined said Whoof! 因为这个时候的this已经不是dog了,处理这个问题,我们就需要:
dogBark = dogBark.bind(dog);就相当于把dogBark的this设定成dog了,就这么个操作。这个**********(bind(dog))的做法就会导致在全局作用域下,不管什么地方call这个function,他永远是针对于dog这个object的,不会再去根据“this”关键字的变化而去处理其他的object。************
https://blog.csdn.net/Jutal_ljt/article/details/53381670

- *************
- EVENTLISTENER
- *************
事件就是类似于onclick,onhover这类的行为被触发,但是事件的触发并不是针对一个单独的object的,一个事件是在全局都可以感知到的,一个button 被触发,最外层的body也是知道的,那么可能我们只需要改变某个被触发的元素,但也有可能我们需要改变被触发元素的parent元素,这个时候就涉及到一个时间顺序问题,有的时候我们希望先改变parent level,有的时候我们希望先改变child level,这就涉及到一个capture还是bubble的问题,MicroSoft和netscape有不同的原则,但是现在的浏览器和javascript支持capture和bubble两种操作方式,只需要在addEventListener('click', funcName, true/false)的第三个parameter输入true false选项就可以了,true=》capture;false=〉bubble,default=》false;
https://www.youtube.com/watch?v=BtOrr7oTH_8
STATE中还有一个关键点:如果我们需要根据之前的state的值来得到一个新的值,我们需要用“function”
原state:
class MyComp extends React.Component {
constructor(props) {
super(props);
this.state = {key:true};
this.methodThatCanBeUsedByClass = this.methodThatCanBeUsedByClass.bind(this);
}
render() {
return (<div><h1>{this.state.key}</h1></div>)
}
}如果我们想要根据this.state来返回目前this.state.key的相反值怎么办?一个toggle?this.setState({key: !this.state.key}) 是不行的,react对state的update不是一个个来的,很有可能是一起打包做一次,这样的话,如果是async的,我们在set的时候,很可能这个this.state和我们真正想得到的结果已经不一样了。所以不能使用this.state来做,方法如下:***********************
this.setState((state)=>({key: !state.key}))
***********************注意,我们为setState带入了一个function,这个function take state作为参数,然后返回这个参数的新的key,这样做就避免了async造成的问题
https://juejin.im/post/599b8f066fb9a0247637d61b
看了掘金这篇文章我们会知道,其实setState可以接受两个参数,一个是“partialState"一个是“callback”, partialState
,它是新的state用来更新之前的state。callback
作为回调函数,会在更新结束之后执行。

也就是说:this.setState((state, prop)=>({manipulate state and prop to return a new state}));是一个固定写法,就是为了避免this.state和this.prop出现异步更新的问题。
************* 一定要注意this.setState,经常中招***************
onChange 这个是在JSX中的:
class Aform extends React.Component {
constructor(props) {
super(props);
this.state = {input: '', submit: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState(state=>({input: event.target.value}));
}
handleSubmit(event) {
this.setState(state=>({submit: state.input}));
}
render() {
return (
<div><form onSubmit={this.handleSubmit}>
<input value={this.state.input} onChange={this.handleChange} />
<button type="submit>SUBMIT</button>
</form></div>
);}这个input的value也是在不停变化的,这个变化是来自于每次onChange的update,也就时说,每次我们多打一个字,this.state.input都发生一次变化,并不是append,而是重做。handleSubmit是一个一次性的工作,就是看当时的this.state.input是什么,是什么就把this.state.submit改成什么。
- ****************
- LIFECYCLE
- ****************
就是可以在特定的时候做某件事,比如在render图像之前,之后。。。
componentWillMount() {} : 在render之前做某事
componentDidMount() {} :
this.state = {activeUsers: null}componentDidMount() {
setTimeout(()=>{this.setState({activeUser: 1273})}, 1000);
}render() {
return <div><h1>Active Users: {this.state.activeUsers}</h1></div>
}
这段代码就将didMount的功能展示出来了,也就是说在render之后,didMount就会自动被call,然后会执行内部的代码,我们是让他在1秒后将activeUser改变成1273,我们也会清晰的从browser中发现,render一开始,Active User是空的,过了一秒变成1273.还有就是在执行componentDidMount()之后再放置一个componentWillUnmount(),这个方法的作用就是将降一些在componentDidMount()方法中放置的一些eventListener的东西清除掉,否则会产生某些eventListener可能一直在执行的问题。life cycle来说也就是是一个删除后的清理工作。
**********如何unmount?***********
shouldComponentUpdate() {}:
react的原则就是当component收到新的state或者是props的时候,他就会开始re render,但是这对性能是不优化的,我们应该让他在发现props或者states和之前的counterpart不一样的时候才去做修改,也就是说,if(currentProps != previousProps || currentState != previousState) { render() {updated view}.shouldComponentUpdate(nextProps, nextState) {
return nextProps == this.props && nextState == this.state ? false : true; //true就是要update
}
componentDidUpdate() {}:
这个顾名思义,就是在render的东西被改变之后,但是这个和componentDidMount有什么区别???********************
setTimeout:
setTimeout(function(){return someValue}, 1000); 两个参数,一个function,一个毫秒数。
Style
React也可以inline的添加style:添加方式:style={{color: "red", fontSize: "75"}}
注意这种方式首先是value需要用引号套起来,其次就是不能有kabab-case, font-size就不OK了, 要用fontSize,还有就是px这类的可以省略。
**********
&&
***********
很重要: (a&&b) return的是什么?
如果a==false,那么直接return false,如果a!=false,return b|| 也是一个道理
a||b, 如果a为truthy value那么return a,否则return b。所以说在我们做JSX内部的判断的时候,我们就可以{condition && <element>} 如果condition 为false,那么就直接一个falsy value,那么就不会return 任何东西,curly braces中间也就是套了一个falsy的value,那么也不会有任何的html返回去,如果前者condition为真,那么后面的这个element 就会被返回去,这个很有效,省去写if else和turnary statement
react 优先级概念,在碎片时间进行高优先级的操作,react fiber
react 与 vue的对比:
react 灵活性更好,处理复杂业务时选择多,
vue 灵活性差,api做的好,面对用户简单一些的可以用vue
搭建react js 开发环境
添加reactjs的方法:1.html 加script标签
2。用脚手架,react create app。。。
grunt,webpack编写脚手架。
脚手架也可以公司各自建立。
最好使用官方的,使用简单,定制性好。create-react-app
code:
npm install -g create-react-app
create-react-app my-app
cd my-app
npm start
脚手架会自动生成下面的文件

首先了解一下package.json,这其实是node的一部分,是node的一个包文件,使项目变为一个node的包。这个package.json应该是node的配置文件,内容如下。

PWA: progressive web application
register service worker: 可以帮助浏览器存储网页,用来以后离线观看。也就是app化。
app.test.js 适用于自动化测试的。
manifest.json里面存的也是关于register service worker 相关的内容,也就是app形式展示的问题,里面可以设置离线http app的icon啊这些东西。

REACT 就是一个个小的组件,前段组件化。
引用关系:
import React { Component } from ‘react’ 或者 const Component = React.Component
只要用了JSX,我们就一定要引用React。render函数中的标签都是JSX
如果使用JSX 标签语法,如果是自定义的组件,要大写。<App /> (<app />不认)
reactDom就是用于把react的组件连接到html文件的手段。
import {Fragment} from 'react'
这个代码的意义就在于避免了每个JSX组件都是一个div有时候会造成css排版上的问题,这样一来,<Fragment></Fragment>里面的代码就会既被看成是一个代码块,同时右可以不是div形式存在。
注意: 下面代码的第38行,我们要注意,onclick接受的是一个函数,并不是执行这个函数,我之前想deleteMessage(idx)并且直接带入idx进去,这时候其实就是执行一个函数了,而不是把函数作为变量带进去,这个有的时候会有一点confusing。

如果我想带入<h1>Hello World<h1>这种带有样式的数据,并且希望网页给予现实的话就要这么写:
<li key={idx(or uuid) onClick={()=>deleteMessage(idx)} dangerouslySetInnerHTML={{__html: ele}}
- *****有一些关键字,react自留,for:htmlFor, class: className, onclick: onClick
destructuring assginment:
let array = [1,2,3]
[a, b, c] = array
// a=>1, b=>2, c=>3let example = {hello: "world"}
let {hello} = example
//hello=>"world"

- ****注意最后一行的return {messages: messages} 可以用 return {messages}来代替,es6的语法糖,也就是说如果hash keyName如果和value的varName一致,则可以用一个varname来代表整个的key value pair
- ****react有单向数据流的特点,意思是,数据是可以从父组件传递到子组件的,但是不能在子组件中修改父组件。这个东西传下来就变成readonly了,只可以把改变父组件的function用props一路传下来,然后调用这个方法即可。
- *** 可以通过强制类型来确定父传子的props的类型。
这种强类型的方式需要import proptypes的库
import PropTypes from 'prop-types';
Component.propTypes = { test: PropTypes.string.isRequired, 这样一来就要求这个必须是string,而且必须存在。
message: PropTypes.string,
deleteMsg: PropTypes.func,
someOther: PropTypes.oneOfTypes([PropTypes.number, PropTypes.string])//这个就表示someOther这个变量既可以是number,也可以是string};


defaultProps这个属性就是说如果在上面的propTypes中的某一项出现required这种值,而有的时候父组件没有向下传递相应值的时候就会出现报错,这个方式能给一个default值,避免报错
- **** render()这个function就是保证在state或者是props的值有改变的时候,马上就刷新页面。父组件的render执行时,子组件的render也会执行。
- *****虚拟DOM
- react virtual dom的概念就是为了提升性能,因为如果用js来不断的生成real dom,并且比对后,在生成新的dom去替换原有dom的话,就会导致大量的性能损耗,因为生成任何一个dom的话,javascipt都要调用一个web application级别的api,然后去生成对象,如果我们以指定的形式去存储一个虚拟的dom,which is 一个js对象的话,就会非常的节省性能,js对象就是内存上的几个slot而已,init起来也简单,diff起来也简单,
function Item() { return (
<div id="hello"><span>World</span></div>
)
}这个Item function所给我们生成的<div>可以转化成一个js对象
['div', {id: "hello"}, ['span', {}, 'World']]
用createElement实现就是: createElement({'div', {id: "hello"}, createElement({'span', {}, 'World'})}也就是说我们创建的这个每个JSX都可以翻译成: block 类型, block property, block的内容这三个东西的一个array,或是objectJSX只是为了看起来比较简单。
*****************虚拟dom使得性能提升很高
react native可以在原生应用里面识别虚拟dom,我们只需要翻译虚拟dom成为相应的android或是ios的组件。
DIFF virtual DOMS
首先setState是一个异步函数,也就是说并不是你调用了setState之后就直接执行的,而是可能调用之后,batch很多的setState一同执行。
同层比对,pre 的第一层和新的第一层比对,发现有diff,直接重新render,这个看上去有一些资源浪费,就是如果只有第一层有变化也会全局都替换。虽然有点耗性能,但是问题不大。
还有就是key值的问题,我们在做Virtual Dom比对的时候,其实我们是在做两个jsx对象的比对,如果没有key的话,就是两个数组进行比对,两个数组进行比对就要O(n²)的时间复杂度,如果有key的话,直接按key比对,那就是线性的。也就是array=>hash的转化。
?????????????????????????????????
key值要稳定,而且最好不要用index作为key值,因为一个在进行增减的时候,统一元素的index值是有可能发生变化的,如果变化,那么key值不匹配也会浪费性能,但是具体怎么确定key值还需要学习,因为如果直接以内容做key值,产生了同内容的jsx组件怎么办?
?????????????????????????????????
ref:
就是给一个JSX组件添加一个ref的prop,然后呢就把某一个DOM元素连接到class内部的某个variable,方便调用了,以前是用event.target来定位,用ref来做一个link之后,就不用写event.target,在创建函数的时候也不用在去take parameter了。
setState是异步函数,那么也就是说我们在调用他的时候,和其他命令同时执行,可能会引发数据和期待不一致的问题:
this.state = {smKey: "a"};
this.setState({smKey: "smVal"});
console.log(this.smKey)
很有可能该操作的log会是“a“而不是”smVal“,因为setState的异步操作特性,会导致console.log先执行,这样就会出错。解决方法:callbacksetState可以接收两个paramthis.setState({smKey: "smVal"}, ()=>{console.log(this.state.smKey)});
这样就基本不会出错了。
以ref的方式获取DOM的方式不是特别推荐,因为setState的异步特性,会导致ref返回的DOM节点尚未被update或是render完成,会产生错误。
生命周期函数
在某一个时刻,组件会自动调用执行的函数。
render()在state,props发生改变时,他会自动执行。
constructor()也可以理解为一种生命周期函数
initialize=》mount
component will mount 即将被挂载的时候执行
component did mount 挂载之后执行
component will receive props子组件才存在的东西,而且在第一次接收到父组件传值的时候并不会执行,会在第2+次开始执行。
should component update 这个lifecycle hook是要求返回一个boolean的,如果返回false,之后的一系列包括render的生命周期就都不会执行执行
component will update 原理和mount是一样的
component did update 同理mount相关的这两个hook是组件第一次在页面渲染的时候才有用。update相关的这些就是在发生改变的时候会触发prop相关的那个就是只有在新的节点已经形成之后,也就时说只有在第二+次接收到prop变化时才会执行

但是life cycle这个一套东西有什么意义呢?
通过这个方式可以尽量减少虚拟dom的re-render,正常我们虚拟dom在发现某个state或是props有变化,就会立即re-render,通过life-cycle 就可以控制在某些情况下不进行变化。
比如说shouldcomponentupdate可以决定上层数据的变化是不是要重新渲染子层的组件
ajax请求,应该在component did mount中加入,也就是说在mount之前去的ajax 数据,(如果放在render里面,render会不断被执行,ajax也会被来回执行,肯定是不合理的)component will mount也可以放,但是这个以后可能会有一些冲突。
axios 是一个发ajax请求的东西。里面有处理请求的一些东西,暂时不重要。
CSSTransition:这个很值得了解一下,就是可以给一些组件套一个CSSTransition,套上之后,转化成了一个嵌套css的组件,其中也有一些钩子,这些钩子会在
on enter
on entering
on enteredexit, exiting, exited 的情况下被call,然后
我们知道,如果是用的component来做组件,我们必须要有一个render函数,Component中没有对于render的default 方案。
- *********************AJAX 就是异步请求
redux 工作流程
数据层框架
所有数据都放在一个store中
antd 是一个ui框架,比较适合开发sass的相关服务,画风整个比较偏商务一些。
可以直接npm install 进来,然后import相应的组件,比如说 import Input,Button这些,注意这个时候不是input了,而是Input,也就是说是组件了,不再是原装的JSX。
说回到redux
安装chrome的redux devtools
const store = createStore(reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
export store;
*************
- ************
- 非常重要的一个收获:
- axios是一个轻量级的在react app中可以使用async的http request 的工具,语法就是axios.get…

还要注意一点,我们这个changeAlertAction function返回的是一个函数,而正常的redux只能接受返回对象的函数,但是我们用了thunk中间件之后,就可以让store去dispatch这种返回函数的function,也就是说有了thunk之后,store在dispatch之前会做判定,看这个action对应的返回的type然后决定是否执行一下这个结果,如果是对象本身则不执行,如果是函数就执行,这个的好处就在于可以在action中加入ajax的请求,这样也使得componentDidMount函数不那么臃肿。
store.dispatch(action) 的时候,如果action是一个函数,那么dispatch是可以被传递进到这个函数里面的,这是为什么呢?
看这段代码:export const getTodoList = () => {
return () => {
axis({
method: "get",
url: "https://jsonplaceholder.typicode.com/posts/1",
responseType: "stream",
headers: { "Access-Control-Allow-Origin": "*"}
}).then(res=>{
const data = res.data.title;
const action = {type: "loadInitMessage", value: data};
dispatch(action);
});};};
Object assign 这个方法也很厉害
Object.assign(target, source1, source2)这个做法就是会返回一个新的对象,对source1,source2,和target进行整合,source2 的priority最高,source1的第二,target最低,priority高的可以override priority低的object
举例:let newTarget = ({a: 2, b: 3, c: 4}, {a: 3, b: 5, c: 2}, {a: 100, b: 1000, c: 10000, d: 1});
返回的newTarget值就应该是{a: 100, b: 1000, c: 10000, d: 1}这个对于复制object很有好处。
thunk 这种中间件的执行就是在action和reducer之间加了一层缓冲层,也就是,在action被create之后,逐个遍历这些中间件,然后让中间件们对action(无论是对象还是function还是什么别的东西)进行操作,thunk就会把function转化成起返回的值,这就很有意思了。但是还是有一点混乱,就是为什么写thunk的时候最后一步并没有return任何东西,而是dispatch了一个(action)这个结果好像不会返回一个action,但是在调用的时候确实用dispatch(getTodoList())直接call,这是为什么?

redux saga
异步代码拆分的中间件,可以代替redux thunk
yarn add redux-saga
注意saga使用了es6 的generator函数,
function* funcname() { yield 'first result'; yield 'second result'; return 'last result'};funcname.next();
{value: 'first result', done: false}funcname.next();
{value: 'second result', done: false}funcname.next();
{value: 'last result', done: true}redux-saga相对来说比较复杂1. 创建safas.js, 然后import到store的index文件中
import todoSagas from './sagas';
2. 创建一个sagaMiddleware的对象
const sagaMiddleware = createSagaMiddleware;
3. 创建一个composeEnhancer
const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__() : compose;
4. 创建一个enhancer把这几个中间件连起来
const enhancer = composeEnhancer(applyMiddleware(sagaMiddleware));
5. 创建store
const store = createStore(reducer, enhancer);
6. 直接run这个middleware
sagaMiddleware.run(todoSagas);