通过前面 script 的方式虽然也能完成 React.js 的开发(上一篇的文章中的方式)
但是,却存在这很大的问题,模块化怎么实现
create-react-app
Create React App
基于 Node.js 编写的命令行工具,通过它可以快速生成 React.js 项目
内置了 Babel、Webpack 等工具帮助我们实现 ES6+ 解析、模块化解析打包
通过它,我们可以使用 模块化 以及 ES6+ 等更新的一些特性
同时它还内置 ESLint 语法检测工具、Jest 单元测试工具
还有一个基于 Node.js 的 WebServer 帮助我们更好的在本地预览应用(热更新)
下载执行后即可搭建项目
npm
、yarn
、npx
都可以npm
的方式 npm i -g create-react-app
yarn
的方式 yarn global add create-react-app
npm
方式create-react-app 项目名称
npx
方式(npx存在)npx create-react-app 项目名称
npm start
npm run build
需要继承React,{Component}
组件
组件内部需要有render()
方法,render()
方法内部的标签必须return
返回
需要export default
导出
import React,{Component} from "react";
class FriendList extends Component{
// 函数放置位置
render() {
return (
// 放置页面渲染的标签
<div className="friend-list"> </div>
);
}
}
export default FriendList;
引入静态资源
直接引入即可,不需要手动使用
import "./FriendList.css"
嵌套循环
在create-react-app
的实例中是要求用到key
的
直接在一个整体中嵌套某些情况下会显得代码臃肿,可阅读性下降
所以这里直接抽取出来处理
Object.keys(data)
返回处理为一个数组(仅仅是为了借用处理后的length值)属性名:item
和属性值:data[item]
传递给子组件key
,这里绑定index
只是为了避免页面警告,实际使用时key
有讲究的 return (
<div className="friend-list">
{
Object.keys(data).map((item,index)=>{
return (
<FriendGroup
name = {item}
key={index}
value = {data[item]}
/>
)
})
}
</div>
);
let {title,list} = this.props.value;
render(){
console.log(this.props)
let {title,list} = this.props.value;
return (
<div className="friend-group">
<dt>{title}</dt>
{
list.map((item,index)=>{
return (<dd key={index}>{item.name}</dd>)
})
}
</div>
)
}
类似于vue
组件中的data
属性
state
的主要作用是用于组件保存、控制、修改自己的可变状态
在组件内部进行初始化,也可以在组件内部进行修改,但是组件外部不能修改
class App extends Component {
state={
nub:23,
name:"Mr_Qin",
say:"hello"
}
render(){
let {nub} = this.state;
console.log(this.state)
return (<div>
<p> {this.state.nub} </p>
</div>)
}
}
类组件中,定义constructor
,一定要接受props
,调用super(props)
class App extends Component {
constructor(props){
super(props)
this.state={
nub:0
}
}
fn=()=>{
this.setState({
nub:this.state.nub + 1
})
}
render(){
// 通过this调用箭头函数
let {nub} = this.state;
return (<div>
<p> {this.state.nub} </p>
</div>)
}
}
state
中的属性需要通过this.setState()
去设置,直接通过this.state.属性=属性值
是不能操作的
class App extends Component {
state={
nub:23,
name:"Mr_Qin",
say:"hello"
}
render(){
// this 指向当前组件
let {nub} = this.state;
return (<div>
<p> {this.state.nub} </p>
<button
onClick={()=>{
// 只去查找对相应的属性 不是整体覆盖
this.setState({
nub:nub+1,
sex:"男"
})
}}
>add one year</button>
</div>)
}
}
class App extends Component {
state={
nub:23,
name:"Mr_Qin",
say:"hello"
}
fn=()=>{
this.setState({
nub:this.state.nub + 1
})
}
render(){
// 通过 this调用箭头函数(普通函数 this会跑偏)
let {nub} = this.state;
return (<div>
<p> {this.state.nub} </p>
<button
onClick={this.fn}
>add one year</button>
</div>)
}
}
this.setState()
修改属性时,只去查找对相应的属性 不是整体覆盖组件的第1个参数是 props
用来接收父级传递的信息
组件中的 return
(必写) 定义该组件要渲染的内容
没有生命周期,没有 this
没有 state
在 16.7 (测试版)之前,函数组件一直当做纯渲染组件 来使用
import React from 'react';
function Child(props){ // props ⇒ 接收父组件的数据
return <h3>{props.info}</h3>
}
function App(){
// this ⇒ undefind
console.log(this)
return (
<div>
来啊 快活啊
// 子组件
<Child info="诶嘿" />
</div>)
}
export default App;
与类式组件中的state
功能相近,用于数据管理
使用前需要引入依赖 import {useState} from 'react';
let [属性名,修改方法] = useState(属性名的初始值)
function Child(props){
console.log(props.data)
return (
<div>
<h3>{props.data.name}</h3>
<h3>{props.data.age}</h3>
</ div>
)
}
function App(){
let [data,setData] = useState({
name:"浩克",
age:24
})
return (
<div>
<Child data={data} />
<button
onClick={()=>{
// 会覆盖之前的数据
setData({
name:"疯狂的麦咭"
})
}}
>变身</button>
</div>)
}
useStae
修改数据,会直接覆盖原先的值组件传参 | 接收
传参
在组件调用的位置属性名=属性值
传递
...
return (
<FriendGroup
name = {item}
key={index}
value = {data[item]}
/>
)
接收
创建组件的文件中this.props
去调用拿到数据
class FriendGroup extends Component{
render(){
console.log(this.props)
// 这里去接收传递的数据
let {title,list} = this.props.value;
return (
<div className="friend-group">
<dt>{title}</dt>
</div>
)
}
}
类似于制作一个函数传递给子组件,然后允许子组件调用函数,将结果返回,父组件拿到结果后处理
传参
在组件调用的位置属性名=属性值
传递
...
return (
<FriendGroup
name = {item}
key={index}
value = {data[item]}
isOpen= {isOpen}
changeOpen={this.changeOpen}
/>
)
接收
创建组件的文件中this.props
去调用拿到数据
class FriendGroup extends Component{
render(){
// 这里去接收传递的数据
let {name,isOpen,changeOpen} = this.props;
let {title,list} = this.props.value;
return (
<div className="friend-group">
<dt
onClick={()=>{
changeOpen(name)
}}
>{title}</dt>
</div>
)
}
}
就像是在组件外部设置了一个仓库,在仓库中 获取 / 存放
定义仓库
文件名为context.js
内部代码是固定的
import {createContext} from "react"
let context = createContext();
let {Consumer,Provider}= context;
export default context
export {Consumer,Provider}
传参
Provider
是一个标签的存在,传递的数据可以放在标签上
包裹了父组件
import {Provider} from "./context"
// Provider 是一个标签的存在,传递的数据可以放在标签上
class App extends Component {
render(){
return (
<Provider value={
{info:"测试数据"}
}>
<div>
<FriendList />
</div>
</Provider>)
}
}
export default App;
接收
Consumer
也是标签的存在,标签内部可以拿到数据
在子组件的子组件中使用跨组件了
import {Consumer} from "./context"
class FriendGroup extends Component{
render(){
// 这里去接收传递的数据
let {name,isOpen,changeOpen} = this.props;
let {title,list} = this.props.value;
return (
<div className="friend-group">
<dt
onClick={()=>{
changeOpen(name)
}}
>{title}</dt>
<dd>
<Consumer>{(val)=>{return val.info}}</Consumer>
</dd>
</div>
)
}
}