一:安装运行和初识
zh-hans.reactjs.org/docs/render…
1:react脚手架 对项目进行开发部署
1:安装脚手架
npm i -g create-react-app
2:创建项目
create-react-app 项目名称
3:启动项目
cnpm start
或者
npx create-react-app 项目名
cd 项目名
npm strat
2:项目初次生成目录结构
yarn.lock:项目依赖的安装包版本号会在这里做一些限制。
README.md:关于项目的说明文件。
package.json:node的包文件,关于项目的一些介绍及一些项目的指令等。
gitignore:如果项目是用git管理的,有些文件不想上传到git仓库里,可以把文件定义到该文件中。
node_modules:项目依赖的第三方的包,是脚手架实现自己功能依赖的一些外部的文件。
public 文件夹下:
favicon.ico:项目图标,可以自己制作一个ico图标,取名为favicon.ico,覆盖该文件。
index.html:项目的首页。
manifest.json:定义网页快捷方式。
src目录下:
index.js:整个程序的入口文件。
registerServiceWorker.js :(pwa)用户第一次访问网页需要联网,下次即使断网,也依然可以显示。
如果有内容需要缓存,就会给缓存起来
App.test.js:项目测试文件。组件的测试
setupTests.js 相对于index.js的测试
3:必要的项目结构
public : 放公共的静态资源
src : 放用户写的代码
package.json
App.js 是项目第一个页面,可以修改这个文件,查看页面效果
index.js 是项目的入口
二:jsx语法
1.介绍:JSX,是一个 JavaScript 的语法扩展。我们建议在 React 中配合使用 JSX,JSX 可以很好地描述 UI 应该呈现出它应有交互的本质形式。
2.语法说明:
jsx语法: js语法 + html语法
只要遇到标签,比如:<div></div>,这时按html语法解析
只要遇到{},这时就按js语法解析,{}中可以放变量,表达式
<div>{username}</div>
3.注意:
1.jsx语法中如果标签需要添加类名,这时需要使用 className 属性
2.tabindex 则变为 tabIndex(是html属性 tabindex 属性规定元素的 tab 键控制次序(当 tab 键用于导航时)。)
3.添加js注释,需要添加到{}中,比如{ /* 注释内容 */}
三:渲染函数
一个元素:
const element = <h1>Hello, world</h1>;
将一个元素渲染为DOM:
使用ReactDOM的render函数
ReactDom.render(<组件/ >,document.getElementById('root'))
const element = <h1>Hello, world</h1>;
ReactDOM.render(element, document.getElementById('root'));
四:组件和props
组件
!!!!!注意:1.组件名称必须以大写字母开头
2.调用ReactDom.render(<Welcome />)时,组件是以标签形式调用的,写单标签时必须有结束符号
3.组件调用可以不在ReactDom.render方法中,可以在页面中任何位置
细节说明:
1.function 和 class 关键字后的名称就是组件名称。
2.return 后就是页面结构,如果页面结构比较复杂,需要使用小括号括起来
3.return 后的页面结构,只能有一个顶级标签,顶级标签不能有兄弟元素
4.组件是页面结构,如果这个组件有自己的css样式,在当前组件中通过import引入
props 使用分两步:
1.组件调用时,组件上通过定义属性,传递数据
2.组件内部通过 this.props.属性名称 得到传递的值
举例:调用:<About username="jim" upwd='k123' />
定义:class About extends React.Component{
render(){
return (
<div>
<p>姓名:{this.props.username}</p>
<p>密码:{this.props.upwd}</p>
</div>
)
}
}
3.props是单向传递,也就是说只能从父组件传到子组件,子组件传递给父组件时,不能使用 属性传递的形式props传回去
4.props是只读属性
拿到值后做任何操作都不可改变props对象上的值,当然你可以使用它赋值去做其他改变
1:定义组件的方式有两种:
1:函数形式
function ListItem(props) {
console.log(props);
return (
<div>这是一个函数式的组件</div>
);
}
2:class类形式的
class ChildrenCom extends React.Component {
constructor(props) {
super(props);
this.state = {
msg: "helloworld",
};
}
render() {
return (
<div>
这是一个class式的组件
</div>
);
}
}
3:导出
export default 组件
2:使用组件
1:引入 import '组件' from '地址'
props
调用组件时可以给组件传递参数,props是用来接受传递过来参数的一个属性
组件之间的传值
知识点: state props setState({})
父组件传递数据给子组件
// 父传子
// 注意:props可以传递函数,props可以传递父元素的函数,就可以去修改父元素的state,从而达到传递数据给父元素。
// 在父元素中使用state去控制子元素props的从而达到父元素数据传递给子元素
class ParentCom extends React.Component {
constructor(props) {
super(props);
this.state = {
fatherToChild: "hello",
};
}
render() {
return (
<div>
<button>
父组件
</button>
<ChildrenDom FatherToChild={this.state.fatherToChild}></ChildrenDom>
</div>
);
}
}
class ChildrenDom extends React.Component {
constructor(props) {
super(props);
console.log("子组件的props", props);
}
render() {
return (
<div>
<h1}>这个是子组件{FatherToChild}</h1>
</div>
);
}
}
子组件传递数据给父组件
// 调用父元素的函数从而操作父元素的数据,从而实现数据从子元素传递至父元素
class ParentCom2 extends React.Component {
constructor(props) {
super(props);
this.state = {
childData: null,
};
}
render() {
return (
<div>
<h1>子元素传递给父元素的数据:{this.state.childData}</h1>
<ChildrenCom setChildData={this.setChildData}></ChildrenCom>
{/* 把函数传递给了子组件,子组件可以在props看到 ,可以调用 */}
</div>
);
}
setChildData = (data) => {
this.setState({
childData: data,
});
};
}
class ChildrenCom extends React.Component {
constructor(props) {
super(props);
this.state = {
msg: "helloworld",
};
// this.sendDate = this.sendDate.bind(this)
}
render() {
return (
<div>
<button onClick={this.sendDate}>传递helloworld 给父元素</button>
<button onClick={()=>{this.props.setChildData(this.state.msg)}}>传递helloworld 给父元素</button>
</div>
);
}
sendDate = () => {
//将子组件传递给到父组件,实际上时调用父组件的传递进来的方法
this.props.setChildData(this.state.msg);
};
// sendDate(){
// console.log(this); //undefined 需要搭配 this.sendDate = this.sendDate.bind(this) 去绑定this指向
// }
}
五: 生命周期函数和state
每一个组件从创建到销毁,过程中会有一些自动执行函数,被称为生命周期函数
componentWillMount(){} 组件将要渲染
render(){} 渲染功能
componentDidMount(){} 组件渲染完毕,组件会进入运行状态
componentWillReceiveProps props发生改变触发
shuouldCompoentUpdate(){ 是否允许组件发生改变
return true 允许组件发生改变
return false 是禁止组件发生改变
}
componentWillUpdate(){} 组件状态将要发生更新
render(){} 渲染功能,这是刚更新页面
componentDidUpdate(){} 组件状态完成更新,再次进入运行状态
componentWillUnmount(){} 组件将要销毁
进行网络请求时,可以将请求的代码写在 componentWillMount和componentDidMount两个生命周期函数中
区别在页面表现形式:
componentWillMount:如果网页加载很慢的情况下,会出现白屏,因为组件还没有渲染
componentDidMount :render完之后,已经加载页面,动态加载数据的部门先空着,稍后慢慢填充
所以一般情况下我们要放在componentDidMount中,除非有特殊情况
举个例子,比如我们的登录,此页面已经登陆过了,当再次打开页面时,直接在右上角显示用户名,不必让页面闪一下(留有一个空白),才能显示用户名。这就是在componentWillMount中的
网速慢得时候先显示请登录,过了一会显示了用户名的情况就是将请求放在了componentDidMount中
根据需求不用,调用不同的生命周期函数
生命周期内部的this ,指向的是 当前的组件
state
state
1.state是组件内部的状态,外部不可访问。
2.使用:
1.需要使用es6的class定义组件
2.在class定义组件中添加,state在constructor中初始化
constructor(props) {
super(props);
this.state = {date: new Date()};
}
3.组件内部就可以使用state了
访问:this.state.属性
修改:this.setState({
属性名:属性值
})
如果更新是异步的,则setState接受一个函数,而不是一个对象
setState((state)=>{
})
六: 事件处理
1.给元素绑定事件
2.React 事件的命名采用小驼峰式(camelCase),而不是纯小写
使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串
3.使用:
<div onMouseOver={this.函数名.bind(this)}></div>
1.on+事件名称,形成事件
2.事件={},大括号中写事件函数,还需要使用bind()把this绑定到当前函数
3.函数定义在class类中,和生命周期函数同级
demo(a,b,event){
}
4.函数调用也可以传参,bind(this,参数1,参数2)
5.事件对象在函数定义中写,有一个关键字叫event
6.不能通过返回 false 的方式阻止默认行为。你必须显式的使用 preventDefault
7.给事件函数绑定this的第二种方式:在构造函数中初始化
constructor(){
this.demo = this.demo.bind(this)
}
demo(){
}
七:条件渲染
实现方式
if、三元表达式
运算符 &&等
八:列表渲染
1.用循环生成页面结构,并填充数据
2.循环生成的元素上要添加key,用来表示是唯一的。
3.使用:
map() 实现遍历
数组.map(function(element,index){
element是元素项
index是下标
})
4.数组遍历方法
for()
map()
filter()
九:表单
1.表单分受控组件和非受控组件
受控组件: state 为“唯一数据源”,setState唯一管理数据
非受控组件:非受控组件将真实数据储存在 DOM 节点中
2.受控组件
1.<input>、 <textarea> 和 <select>
2.使用:如何获取值以及更新值
<input name="username" value={this.state.username} onChange={this.gaibian.bind(this)}>
方法1:使用value值获取和更新值
gaibian(event){
this.setState({
username:event.target.value
})
}
方法2:使用event上的属性target,通过name属性获取和更新值
gaibian(event){
this.setState({
[event.target.name]:event.target.value
})
}
3.<textarea> 不管是设置值还是获取值都使用value属性
4.<select value={this.state.key} onChange={this.sel.bind(this)}>
sel(event){
this.setState({
key:event.target.value
})
}
5.单选按钮
<input type="radio" name='sex' value='nan' onChange={this.selsex.bind(this)}/> 男
<input type="radio" name='sex' value='nv' onChange={this.selsex.bind(this)}/> 女
selsex(event){
// console.log(event.target.value)
this.setState({
sex:event.target.value
})
}
6.多选按钮
<input type="checkbox" vaule="apple" onChange={this.friut.bind(this)}>
<input type="checkbox" vaule="orange" onChange={this.friut.bind(this)}>
<input type="checkbox" vaule="pie" onChange={this.friut.bind(this)}>
friut(event){
let cur = event.target.value;
let arr = this.state.shuiguo;
if(this.state.shuiguo.indexOf(cur) == -1 ){
arr.push(cur)
this.setState({
shuiguo:arr
})
}else{
arr.splice(this.state.shuiguo.indexOf(cur),1)
this.setState({
shuiguo:arr
})
}
}
7.form标签上
<form onSubmit={this.tijiao.bind(this)}>
<input type="submit" value="提交" />
<form>
3:非受控组件
1. 非受控组件,这时表单数据将交由 DOM 节点来处理
2. ref
通过ref可以获取到DOM节点。
定义方式:
1.过时的语法:ref="字符串名称"
<div ref='str'></div>
2.新语法:
创建ref: this.demo = React.createRef()
<div ref={this.demo}></div>
调用:
过时的语法:this.ref名称.属性
新语法:this.ref名称.current
十: 状态提升
1. 通常,多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去。
2. 实现方式:
1.把父级的函数传递给子级
2.在子级中调用父级函数,这时修改的是父级中的状态
3.看到的效果是:所有引入父级这个状态的组件中的值都发生改变。
十一 :组件组合(vue中叫插槽)
1.包含关系(插槽)
1. 在调用组件时,在组件标签内部添加其他代码
2. 在组件内部,通过{this.props.children} 能获取到添加代码
调用:
<FancyBorder color="blue">
<h1 className="Dialog-title">
Welcome
</h1>
<p className="Dialog-message">
Thank you for visiting our spacecraft!
</p>
</FancyBorder>
定义:
class FancyBorder extends React.Component{
render(){
return(
<div>
{this.props.children}
</div>
)
}
}
十二:网络请求数据
1. fetch请求
1.Fetch API 提供了一个 JavaScript接口,用于访问和操纵HTTP管道的部分,该方法提供了一种简单,合理的方式来跨网络异步获取资源。
2.语法:
fetch(url,{
method:'get',
headers:{
"content-type":"application/x-www-form-urlencoded"
},
body:"uname=key&upwd=123",
credentials:"include, same-origin, omit", //是否允许携带cookie
mode: 'no-cors, cors, same-origin' // 是否允许cors跨域
})
.then(function(data){
return data.json() // 解析数据
})
.then(function(res){
console.log(res) //请求到的结果
})
2. 如果是post请求,传递数据格式是:"key=value&key=value"
{
user_id:"iwen@qq.com",
password:"iwen123"
}
=> "user_id=iwen@qq.com&password=iwen123&verification_code=crfvw"
nodejs中已经封装好一个组件,querystring
querstring.parse("user_id=iwen@qq.com&password=iwen123")
=>{user_id:"iwen@qq.com",password:"iwen123"}
querystring.stringify({
user_id:"iwen@qq.com",
password:"iwen123"
})
=>"user_id=iwen@qq.com&password=iwen123"
十三: 跨域
解决方法:
1.cors :后台配置
2.jsonp :
下插件:fetch-jsonp
使用插件
3. 代理
参考地址:https://github.com/facebook/create-react-app/blob/45bc6280d109b7e353ffaa497a0352c9d040c36d/docusaurus/docs/proxying-api-requests-in-development.md
--------------------------------------------------------------------------------------------
create-react-app 这个一键搭建环境命令生成的代码也可以实现代理
原先通过fectch请求这个路径fecth('http://localhost:3001/user')。可使用代理方式有两种如下:
1.在package.json文件中配置
1.配置
{
"proxy": "http://localhost:3001"
}
2.重启服务器
3.修改fetch请求中的路径
fetch('/user')
.then(data=>data.json())
.then(res=>{
console.log(res)
})
2.使用中间件
1.下载:npm install http-proxy-middleware --save
2.在src目录下创建setupProxy.js文件
3.在setupProxy.js文件中配置
const proxy = require('http-proxy-middleware');
module.exports = function(app) {
app.use(proxy('/*', { target: 'http://localhost:3001/' }));
};
4.重启服务器