|
此系列文章用来记录我的学习历程。
今日任务:
fcc:
1.React
2.React和Redux配合
3.Redux
React
简介
React 是由 Facebook 创建和维护的开源视图库。 它是渲染现代 Web 应用程序用户界面(UI)的好工具。
React 使用名为 JSX 的 JavaScript 语法扩展,可以直接在 JavaScript 中编写 HTML。
因为 JSX 是 JavaScript 的语法扩展,所以实际上可以直接在 JSX 中编写 JavaScript。要做到这一点,只需在花括号中包含希望被视为 JavaScript 的代码:
{ 'this is treated as JavaScript code' }
Ract基础:
①简单的编写
要点:
关于嵌套的 JSX,需要知道的一件重要的事情,那就是它必须返回单个元素。
这个父元素将包裹所有其他级别的嵌套元素。
示例:
//有效示例
<div>
<p>a</p>
<p>b</p>
<p>c</p>
</div>
//无效示例
<p>a</p>
<p>b</p>
<p>c</p>
②在JSX中注释
使用{/* */}语法注释
const JSX = (
<div>
{/*
<h1>This is a block of JSX</h1>
<p>Here's a subtitle</p>
*/}
</div>
);
③渲染HTML元素为DOM树
方法:ReactDOM.render(componentToRender, targetNode)
其中第一个参数是要渲染的 React 元素或组件,第二个参数是组件将要渲染到的 DOM 节点。
代码编辑器中有一个简单的 JSX 组件。使用document.getElementById()?来选择要渲染到的 DOM 节点。
示例:渲染ID为'challenge-node'
ReactDOM.render(JSX,document.getElementById('challenge-node'))
④用className作为类关键字
JSX和JavaScript不同,不能用class命名类,要使用className
const JSX = (
<div className="myDiv">
<h1 >Add a class to this div</h1>
</div>
);
⑤创建一个React组件
定义 React 组件的另一种方法是使用 ES6 的?class语法。 在以下示例中,Kitten?扩展了React.Component:
class Kitten extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<h1>Hi</h1>
);
}
}
⑥使用React渲染嵌套组件
在render之后加入标签即可<组件名称 />
class Kitten extends React.Component {
? constructor(props) {
? ? super(props);
? }
? render() {
? ? return (
? ? ? <h1>Hi</h1>
? ? ? <zujian />
? ? );
? }
}
⑦将class组件渲染到DOM树
语法:?ReactDOM.render(componentToRender, targetNode)。 第一个参数是要渲染的 React 组件。 第二个参数是要在其中渲染该组件的 DOM 节点。
传递到ReactDOM.render()?的React 组件与 JSX 元素略有不同。 对于 JSX 元素,传入的是要渲染的元素的名称。 但是,对于 React 组件,需要使用与渲染嵌套组件相同的语法,例如ReactDOM.render(<ComponentToRender />, targetNode)。 此语法用于 ES6 class 组件和函数组件都可以。
在后台引入了?Fruits?和?Vegetables?组件。 将两个组件渲染为?TypesOfFood?组件的子组件,然后将?TypesOfFood?渲染到 DOM 节点, 在这个挑战中,请渲染到?id='challenge-node'的?div?中。
class TypesOfFood extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h1>Types of Food:</h1>
{/* 修改这行下面的代码 */}
< Fruits />
< Vegetables />
{/* 修改这行上面的代码 */}
</div>
);
}
};
// 修改这行下面的代码
ReactDOM.render(<TypesOfFood/>,document.getElementById("challenge-node"));
⑧props
1.访问props
无状态函数组件:
假设有一个?App?组件,该组件渲染了一个名为?Welcome?的子组件,它是一个无状态函数组件。 可以通过以下方式给?Welcome?传递一个?user?属性:
<App>
<Welcome user='Mark' />
</App>
由于?Welcome?是一个无状态函数组件,它可以像这样访问该值:
const Welcome = (props) => <h1>Hello, {props.user}!</h1>
ES6 类组件:
任何时候,如果要引用类组件本身,可以使用?this?关键字。 要访问类组件中的 props,需要在在访问它的代码前面添加?this。 例如,如果 ES6 类组件有一个名为?data?的 prop,可以在 JSX 中这样写:
{this.props.data}
2.PropTypes定义props类型
React 提供了有用的类型检查特性,以验证组件是否接收了正确类型的 props。 例如,应用程序调用 API 来检索数据是否是数组,然后将数据作为 prop 传递给组件。 可以在组件上设置?propTypes,以要求数据的类型为?array。 当数据是任何其它类型时,都会抛出警告。
当提前知道 prop 的类型时,最佳实践是设置其?propTypes。 可以为组件定义?propTypes?属性,方法与定义?defaultProps?相同。 这样做将检查给定键的 prop 是否是给定类型。 这里有一个示例,表示名为?handleClick?的 prop 应为?function?类型:
MyComponent.propTypes = { handleClick: PropTypes.func.isRequired }
小练习:
1.创建一个可以控制的输入框
?通常,如果 React 组件具有用户可以键入的输入字段,那么它将是一个受控的输入表单。
代码编辑器具有一个名为?ControlledInput?的组件框架,用于创建受控的?input?元素。 组件的?state?已经被包含空字符串的?input?属性初始化。 此值表示用户在?input?字段中键入的文本。
class ControlledInput extends React.Component {
constructor(props) {
super(props);
this.state = {
input: ''
};
// 修改这行下面的代码
this.handleChange=this.handleChange.bind(this)
// 修改这行上面的代码
}
// 修改这行下面的代码
handleChange(event){
this.setState({
input: event.target.value
})
}
// 修改这行上面的代码
render() {
return (
<div>
{ /* 修改这行下面的代码 */}
<input value={this.state.input} onChange = {this.handleChange.bind(this)}/>
{ /* 修改这行上面的代码 */}
<h4>Controlled Input:</h4>
<p>{this.state.input}</p>
</div>
);
}
};
在输入框中键入时,文本由?handleChange()?方法处理,文本被设置为本地?state?中的?input?属性,并渲染在页面上的?input?框中。 组件?state?是输入数据的唯一真实来源。
2.创建一个可以控制的表单
class MyForm 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({
input: event.target.value
});
}
handleSubmit(event) {
// 修改这行下面的代码
event.preventDefault()
this.setState({
submit:this.state.input
})
// 修改这行上面的代码
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
{/* 修改这行下面的代码 */}
<input value={this.state.input} onChange={this.handleChange}/>
{/* 修改这行上面的代码 */}
<button type='submit'>Submit!</button>
</form>
{/* 修改这行下面的代码 */}
<h1>{this.state.submit}</h1>
{/* 修改这行上面的代码 */}
</div>
);
}
}
注意:?还必须在提交处理程序中调用?event.preventDefault(),以防止将会刷新网页的默认的表单提交行为。
⑨React组件中的特殊方法:
生命周期方法
componentWillMount()?
componentDidMount()?
shouldComponentUpdate()?
componentDidUpdate()?
componentWillUnmount()
………………
1.componentWillMount()函数
????????当组件被挂载到 DOM 时,componentWillMount()?方法在?render()?方法之前被调用。 在componentWillMount()中将一些内容记录到控制台 -- 可能需要打开浏览器控制台以查看输出。
2.componentDidMount()函数
????????某些时候,大多数 web 开发人员需要调用 API 接口来获取数据。 如果正在使用 React,知道在哪里执行这个动作是很重要的。
????????React 的最佳实践是在生命周期方法?componentDidMount()?中对服务器进行 API 调用或任何其它调用。 将组件装载到 DOM 后会调用此方法。 此处对?setState()?的任何调用都将触发组件的重新渲染。 在此方法中调用 API 并用 API?? 返回的数据设置 state 时,一旦收到数据,它将自动触发更新。
componentDidMount() {
setTimeout(() => {
this.setState({
activeUsers: 1273
});
}, 2500);
}
3.在React中添加内联样式
const styles = {
color: 'purple',
fontSize: 40,
border: "2px solid purple",
};
// 修改这行上面的代码
class Colorful extends React.Component {
render() {
// 修改这行下面的代码
return (
<div style={styles}>Style Me!</div>
);
// 修改这行上面的代码
}
};
Redux:
简介:Redux 是一个状态管理框架,可以与包括 React 在内的许多不同的 Web 技术一起使用。
①创建一个Redux store
Redux?store?是一个保存和管理应用程序状态的state, 可以使用 Redux 对象中的?createStore()?来创建一个 redux?store, 此方法将?reducer?函数作为必需参数,?reducer?函数将在后面的挑战中介绍。该函数已在代码编辑器中为你定义, 它只需将?state?作为参数并返回一个?state?即可。
const reducer = (state = 5) => {
return state;
}
const store = Redux.createStore(reducer)
简写
const store = Redux.createStore(
(state = 5) => state
);
let currentState=store.getState()
②创建一个Redux Action
const action={
type:'LOGIN'
}
③定义一个Action Creater
const action = {
type: 'LOGIN'
}
// 在这里定义一个动作创建器:
function actionCreator(){
return action
}
④分发action event并在store处理Action
4.1分发action event
dispatch?方法用于将 action 分派给 Redux store, 调用?store.dispatch()?将从 action creator 返回的值发送回 store。
const store = Redux.createStore(
(state = {login: false}) => state
);
const loginAction = () => {
return {
type: 'LOGIN'
}
};
// 在这里发送 action:
store.dispatch(loginAction());
4.2store处理Action
?Redux 中的 Reducers 负责响应 action 然后进行状态的修改。?reducer?将?state?和?action?作为参数,并且它总是返回一个新的?state。
const defaultState = {
login: false
};
const reducer = (state = defaultState, action) => {
// 修改这行下面的代码
if (action.type === "LOGIN") {
return {
login: true
};
} else {
return state;
}
// 修改这行上面的代码
};
const store = Redux.createStore(reducer);
const loginAction = () => {
return {
type: 'LOGIN'
}
};
⑤使用const声明
const LOGIN='LOGIN';
const LOGOUT='LOGOUT';
⑥注册Store监听器
在 Redux?store?对象上访问数据的另一种方法是?store.subscribe()。
这允许将监听器函数订阅到 store,只要 action 被 dispatch 就会调用它们。 这个方法的一个简单用途是为 store 订阅一个函数,它只是在每次收到一个 action 并且更新 store 时记录一条消息。
const add = () => (count+=1);
store.subscribe(add);
⑦组合多个reducer
?Redux 的第一个原则:所有应用程序状态都保存在 store 中的一个简单的 state 对象中。?
因此,Redux 提供 reducer 组合作为复杂状态模型的解决方案。 定义多个 reducer 来处理应用程序状态的不同部分,然后将这些 reducer 组合成一个 root reducer。 然后将 root reducer 传递给 Redux?createStore()方法。
const rootReducer = Redux.combineReducers({
auth:authReducer,
count:counterReducer
})
⑧发送Action Data给Store
const ADD_NOTE = 'ADD_NOTE';
const notesReducer = (state = 'Initial State', action) => {
switch(action.type) {
// 修改这行下面的代码
case 'ADD_NOTE':{
return action.text
}
// 修改这行上面的代码
default:
return state;
}
};
const addNoteText = (note) => {
// 修改这行下面的代码
return {
type:ADD_NOTE,
text:note
}
// 修改这行上面的代码
};
const store = Redux.createStore(notesReducer);
console.log(store.getState());
store.dispatch(addNoteText('Hello!'));
console.log(store.getState());
⑨使用Object.assign拷贝对象
处理对象的一个常用的方法是?Object.assign()。?Object.assign()?获取目标对象和源对象,并将源对象中的属性映射到目标对象。 任何匹配的属性都会被源对象中的属性覆盖。 通常用于通过传递一个空对象作为第一个参数,然后是要用复制的对象来制作对象的浅表副本。 示例:
const newObject = Object.assign({}, obj1, obj2);
这会创建?newObject?作为新的?object,其中包含?obj1?和?obj2?中当前存在的属性。
React和Redux配合
参考链接:学习 React and Redux: React 和 Redux 入门 | freeCodeCamp.org
刷题
我们要先弄清楚React和Redux配合我们要弄清楚他们的关键原则是什么。?
????????React 是提供数据的视图库,能以高效、可预测的方式渲染视图。 Redux 是状态管理框架,可用于简化 APP 应用状态的管理。 在 React Redux app 应用中,通常可创建单一的 Redux store 来管理整个应用的状态。 React 组件仅订阅 store 中与其角色相关的数据, 可直接从 React 组件中分发 actions 以触发 store 对象的更新。
????????React 组件可以在本地管理自己的状态,但是对于复杂的应用来说,它的状态最好是用 Redux 保存在单一位置,有特定本地状态的独立组件例外。 当单个组件可能仅具有特定于其的本地状态时,算是例外。 最后一点是,Redux 没有内置的 React 支持,需要安装?react-redux包, 通过这个方式把 Redux 的?state?和?dispatch?作为?props?传给组件。
①入门
从?DisplayMessages?组件开始。 把构造函数添加到此组件中,使用含两个属性的状态初始化该组件,这两个属性为:input(设置为空字符串),messages(设置为空数组)。
class DisplayMessages extends React.Component {
// 修改这行下面的代码
constructor(props){
super(props);
this.state = {
input :'',
messages:[]
}
}
// 修改这行上面的代码
render() {
return <div />
}
};
②首先在本地管理状态
这一关的任务是完成?DisplayMessages?组件的创建。
首先,在?render()?方法中,让组件渲染?input、button、ul?三个元素。?input?元素的改变会触发?handleChange()?方法。 此外,input?元素会渲染组件状态中?input?的值。 点击按钮?button?需触发?submitMessage()?方法。
接着,写出这两种方法。?handleChange()?方法会更新?input?为用户正在输入的内容。?submitMessage()?方法把当前存储在?input?的消息与本地状态的?messages?数组连接起来,并清除?input?的值。
最后,在?ul?中展示?messages?数组,其中每个元素内容需放到?li?元素内。
class DisplayMessages extends React.Component {
constructor(props) {
super(props);
this.state = {
input: '',
messages: []
}
this.handleChange = this.handleChange.bind(this);
this.submitMessage = this.submitMessage.bind(this);
}
// 在这里添加 handleChange() 和 submitMessage() 方法
handleChange(event){
this.setState({
input:event.target.value
});
}
submitMessage(){
this.setState({
input:'',
messages:[...this.state.messages,this.state.input]
});
}
render() {
return (
<div>
<h2>Type in a new Message:</h2>
{ /* 在这一行下面渲染一个输入框(input),按钮(button)和列表(ul) */ }
<input value={this.state.input} onChange={this.handleChange}/>
<button type="submit" onClick={this.submitMessage}></button>
<ul>{this.state.messages.map(i => <li key={i+1}>{i}</li>)}</ul>
{ /* 修改这行上面的代码 */ }
</div>
);
}
};
③提取逻辑状态给Redux
完成 React 组件后,我们需要把在本地?state?执行的逻辑移到 Redux 中, 这是为小规模 React 应用添加 Redux 的第一步。 该应用的唯一功能是把用户的新消息添加到无序列表中。 下面我们用简单的示例来演示 React 和 Redux 之间的配合。
// 定义 ADD、addMessage()、messageReducer() 并在这里存储:
const ADD='ADD'
const addMessage = (message)=>{
return {
type:ADD,
message:message
};
}
const messageReducer = (state=[],action)=>{
switch(action.type){
case ADD:return state.concat(action.message);
default:return state;
}
}
const store = Redux.createStore(messageReducer);
后续明日再战
|