怎样在领英上做公司网站,兼职做网站在那里接任务,做一元购网站,怎么做网站淘宝转换工具React#xff08;五#xff09;一、受控组件1.什么是受控组件#xff08;v-model#xff09;2.收集表单数据:input和单选框3.收集表单数据:下拉框二、非受控组件三、高阶组件1.什么是高阶组件2.高阶组件的应用13.高阶组件的应用2-注入Context4.高阶组件的应用3-登录鉴权5.高…
React五一、受控组件1.什么是受控组件v-model2.收集表单数据:input和单选框3.收集表单数据:下拉框二、非受控组件三、高阶组件1.什么是高阶组件2.高阶组件的应用13.高阶组件的应用2-注入Context4.高阶组件的应用3-登录鉴权5.高阶组件的应用4-生命周期劫持四、Portals的使用五、Fragment的用法和短语六、React中的CSS1.内联样式style2.CSS模块化编写方式3.less的使用方案4.scss的使用方案5.CSS in JS1ES6模板字符串调用函数2使用styled-components的步骤3模板字符串props接收数据4attrs设置属性默认值5styled-components高级特性6.React中动态添加class一、受控组件 1.什么是受控组件v-model
类似vue中的v-model就是双向数据绑定。
比如下面这两个input框受控组件的条件就是有value值。
但是只有value值读取state中的值不行这样input里的东西就不能改了所以要有onChange事件去修改相应的值实现输入框和state数据的同步。
export class App extends PureComponent {constructor() {super();this.state {name: zzy,age: 18,}}changeInput(e) {console.log(e.target.value);this.setState({name: e.target.value})}render() {let { name } this.state;return (div{/* 1.受控组件 */}input typetext value{name} onChange{(e) this.changeInput(e)}/{/* 2.非受控组件 */}input typetext /h1{name}/h1/div)}
}2.收集表单数据:input和单选框
React文档写的非常非常好去看看
下面是一个提交用户名密码和单选框选中状态的案例
下面这个案例定义了两个输入框分别是用户名和密码。还定义了一个单选框有几个需要注意的地方。 for由于对应js关键字使用htmlFor代替 受控组件的特点上面已经提到必须写value且必须要有onChange事件且该事件要修改对应的数据。 修改数据时我们可以去读取e.target.name找到相应的数据把值修改为 e.target.value这样的话就不用一个一个修改了。键值读取变量用[]包裹 提交的值我们可以根据表单的类别进行限制如果是checkbox那么就收集选中状态checked属性如果是输入框那么就收集value 点击按钮提交表单数据的时候数据已经是最新的了onChange的时候就setState render了那么我们可以拿着最新的数据去发送ajax请求。
export class App extends PureComponent {constructor() {super();this.state {userName: ,password: 0,isAgree: false,}}submitData() {console.log(提交, this.state.userName, this.state.password,this.state.isAgree)}changeInput(e) {console.log(e.target.value);//如果拿单选框的数据那么拿到的是布尔值checkedconst value e.target.type checkbox ? e.target.checked : e.target.value;this.setState({[e.target.name]: value})}render() {let { userName, password,isAgree } this.state;return (divform action{/* 1.用户名 */}label htmlForuserName用户名/labelinputtypetextiduserNamenameuserNamevalue{userName}onChange{(e) this.changeInput(e)}/{/* 2.密码 */}label htmlForpassword/labelinputtypepasswordidpasswordnamepasswordvalue{password}onChange{(e) this.changeInput(e)}/{/* 3.单选框 */}inputtypecheckboxnameisAgreeidmanvalue同意checked{isAgree}onChange{(e) this.changeInput(e)}/label htmlForman同意上述协议/label/formbutton onClick{() this.submitData()}提交表单数据/button/div)}
}3.收集表单数据:下拉框
selectoption valueapple苹果/optionoption selected valuepear莉/optionoption valuepeach桃子/option
/select请注意由于 selected 属性的缘故莉选项默认被选中。React 并不会使用 selected 属性而是在根 select 标签上使用 value 属性。这在受控组件中更便捷因为您只需要在根标签中更新它。例如
export class App extends PureComponent {constructor() {super();this.state {fruit: apple}}submitData() {console.log(提交, this.state.fruit)}handleFruitChange(e) {this.setState({fruit: e.target.value})} render() {let { fruit } this.state;return (divform actionselect value{fruit} onChange{(e) this.handleFruitChange(e)}option valueapple苹果/optionoption valuepear莉/optionoption valuepeach桃子/option/select/formbutton onClick{() this.submitData()}提交表单数据/button/div)}
}这里如果select标签加了个multiple那么意味着可以收集多个value我们可以借助e.target.selectedOptions这个伪数组获取所有被选中的选项拿到它们的值
handleFruitChange(e) {const options Array.from(e.target.selectedOptions);const values options.map(item item.value);this.setState({fruit: values})
} 二、非受控组件
一般不用非受控组件因为这玩意儿就是直接操作DOM
在非受控组件中通常使用defaultValue来设置默认值如果要使用非受控组件中的数据那么我们需要使用 ref 来从DOM节点中获取表单数据。
export default class App extends PureComponent {constructor(props) {super(props);this.myRef createRef();}render() {return (divform onSubmit{e this.handleSubmit(e)}label htmlForusername用户: input typetext idusername defaultValue默认值 ref{this.myRef}//labelinput typesubmit value提交//form/div)}handleSubmit(event) {event.preventDefault();console.log(this.myRef.current.value);}
}三、高阶组件
高阶函数接收一个函数作为参数或者返回一个函数。满足两个条件之一。 JavaScript中比较常见的filter、map、reduce都是高阶函数。
1.什么是高阶组件
高阶组件的英文是 Higher-Order Components简称为 HOC。 官方的定义高阶组件是参数为组件返回值为新组件的函数 也就是说首先 高阶组件本身不是一个组件而是一个函数其次这个函数的参数是一个组件返回值也是一个组件
举个例子
//高阶组件接收一个组件作为参数返回另一个组件
function high(Component) {class newComponent extends React.PureComponent {render() {return (//可以做一些处理比如统一在这里添加name属性Component namezzy/)}}return newComponent;
}//需要添加name属性的组件
class HelloWorld extends React.PureComponent {render() {console.log(this.props.name);//输出namereturn (divHelloWorld/div)}
}//1.返回一个类组件
const Dj high(HelloWorld)export class App extends React.PureComponent {render() {return (div{/* 2.对类进行实例化 */}Dj//div)}
}2.高阶组件的应用1
看下面这个例子定义两个普通组件Component1、Component2我们要给这两个组件的props上塞点数据让它实例化的时候带着这个数据去展示怎么做呢
答案是定义高阶组件enhanceUserInfo返回一个新组件这个新组件把你传进来的组件作为儿子并且把自己身上的数据给他{...this.state.userInfo}这样的话经过处理的Component1、Component2就可以拥有name和age可以通过props读到。
function enhanceUserInfo(OriginComponent) {class NewComponent extends React.PureComponent {constructor(props) {super(props);this.state {userInfo: {name: zzy,age: 18}}}render() {//把一些数据塞到你传进来的组件中return OriginComponent {...this.props} {...this.state.userInfo}/}}return NewComponent
}function Component1(props) {return h1Component1: {props.name}-{props.age}-{props.flag}/h1
}
const NewCom1 enhanceUserInfo(Component1);//也可以这样写
const NewCom2 enhanceUserInfo(function(props) {return h1Component2: {props.name}-{props.age}-{props.sex}/h1
})export class HOC extends PureComponent {render() {return (divh2HOC/h2{/* 如果在这里传值的话传给的是NewComponent */}NewCom1 flag标识/NewCom2 sex男//div)}
}还有个问题如果我们往新组件中添加属性的话是传给谁了呢答案是传给了高阶组件中新组件newComponent的props中我们可以通过{...this.props}再把它们传给你塞进去的组件OriginComponent
3.高阶组件的应用2-注入Context
细品一下其实高阶组件的作用就是在我们要处理的组件上边包个父组件父组件给它加点料然后再把父组件扔出来用。
比如我们如果在App中使用context给下面两个子组件传值
export class App extends PureComponent {render() {return (divh1父组件App/h1myContext.Provider value{{ name: zzy, age: 18 }}HOC/HOC2//myContext.Provider/div)}
}那么很多组件都要接到这个数据如果我们分别取每个子组件定义Consumer去接那真的是非常麻烦此时我们就可以把注入value的这个操作封装一下也就是使用高阶组件。
function enhanceContext(Component) {class NewComponent extends PureComponent {render() {return (divmyContext.Consumer{value {return Component {...value} /}}/myContext.Consumer/div)}}return NewComponent;
}那么我们在HOC和HOC2中就可以通过高阶组件注入value并拿到传进来的value值
export class HOC extends PureComponent {render() {return (divh2子组件1HOC/h2h3HOC拿到传过来的value{this.props.name this.props.age}/h3/div)}
}const newHOC enhanceContext(HOC);
export default newHOC;function HOC2(props) {return (divh2子组件2HOC2/h2h3HOC2拿到穿过来的value{props.name}-{props.age}/h3/div)
}export default enhanceContext(HOC2);4.高阶组件的应用3-登录鉴权
如果我们要实现HOC和HOC2等组件在登录之后才能显示
export class App extends PureComponent {render() {return (divh1父组件App/h1{/* 没登陆的话不展示只有登录了才展示 */}HOC /HOC2 //div)}
}定义高阶组件拦截要展示的组件进行鉴权
function loginAuth(Component) {return (props) {if(localStorage.getItem(token)) {return Component {...props}/}else {return h2没有登录{Component.name}不展示请先登录/h2}}
}export default loginAuth;然后这两个组件导出的时候调用一下就行了然后把新的组件导出新的这个组件来决定页面要展示什么东西
export class HOC extends PureComponent {render() {return (divh2子组件1HOC/h2/div)}
}const newHOC loginAuth(HOC);
export default newHOC;function HOC2(props) {return (divh2子组件2HOC2/h2/div)
}export default loginAuth(HOC2);结果
5.高阶组件的应用4-生命周期劫持
比如我还可以在高阶组件中计算每个组件的挂载时间
function computeInterval(Component) {return class extends PureComponent {componentWillMount() {this.begin Date.now();}componentDidMount() {this.over Date.now();let interval this.over - this.begin;console.log(${Component.name}组件渲染时间为${interval}ms)}render() {return Component {...this.props}/}}
}四、Portals的使用
Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案
ReactDOM.createPortal(React元素哪个容器)import {createPortal} from react-dom;
export class App extends PureComponent {render() {return (divh1App渲染在root容器中/h1{createPortal(h2我是h2我要渲染在zzy容器中/h2, document.querySelector(#zzy))}/div)}
}应用创建一个Model组件让组件标签中间插槽的元素全部进入model容器中该容器是一个固定定位
div idroot/div
div idzzy/div
div idmodel/div#model {position:fixed;left: 50%;top: 50%;background-color: skyblue;transform: translate(-50%, -50%);}import {createPortal} from react-dom;
import Model from ./Model;export class App extends PureComponent {render() {return (divh1App渲染在root容器中/h1{createPortal(h2我是h2我要渲染在zzy容器中/h2, document.querySelector(#zzy))}Modelh1数据结构/h1h2算法/h2h3冒泡排序/h3/Model/div)}
}import {createPortal} from react-dom;export class Model extends PureComponent {render() {return (divh1Model/h1{createPortal(this.props.children, document.querySelector(#model))}/div)}
}五、Fragment的用法和短语
每次我们写结构都要包一个根div并且这个div会在浏览器元素中显示
如果不想在浏览器中显示可以引入Fragment
import React, { PureComponent, Fragment } from react;
export class App extends PureComponent {render() {return (Fragmenth1奥里给/h1h2不用根/h2h3嗷嗷嗷/h3/Fragment)}
}语法糖不用引入直接/
render() {return (h1奥里给/h1h2不用根/h2h3嗷嗷嗷/h3/)}但是这种语法糖在遍历需要绑定key的时候不能写必须要写完整的标签才行噢~
六、React中的CSS
1.内联样式style
就是直接写行内style要求是传入一个对象而且属性名要以小驼峰命名好处是可以读取state中的变量。
export class App extends PureComponent {constructor() {super();this.state {size: 20}}large() {this.setState({size: this.state.size 5})}render() {let {size} this.state;return (divh1 style{{color:red, fontSize: 30px}}奥里给/h1h2 style{{color:skyblue, fontSize:${size}px}}样式/h2button onClick{() this.large()}增大上面的字体/button/div)}
}2.CSS模块化编写方式
如果我们把每个组件的css分别定义相应的文件然后引入那么也是没用的所有的css文件第一次引入后都会默认是全局css不管写哪个文件夹里都是共享类名如果后续还有其他css文件包含相同类名引入同类名样式会被下一个渲染的依次覆盖。
但是我们组件开发肯定是希望每个组件有自己的样式这一点Vue做的很好可以加个scope但是React咋办呢
这里可以用css模块化的编写方案 第一步名字前面加.module .box {border: 1px solid red;
}第二步需要用这里样式的组件中引入
import appStyle from ./App.module.css第三步使用.属性名来读取我们对应的类名
{/* 2.CSS模块化*/}
div className{appStyle.box}h1嗷嗷嗷/h1
/div真的是非常麻烦啊不过好像用的人还挺多的。
3.less的使用方案
参考Ant Design关于安装craco和less的配置
安装carcocreate-react-app config缩写和craco-less
npm install craco craco-less修改package.json
/* package.json */
scripts: {
- start: react-scripts start,
- build: react-scripts build,
- test: react-scripts test,start: craco start,build: craco build,test: craco test,
}然后在项目根目录创建一个 craco.config.js 用于修改默认配置。
//craco.config.js文件
const CracoLessPlugin require(craco-less)module.exports {plugins: [{plugin: CracoLessPlugin,}]
}ok现在就可以在React中定义less并引入使用了
4.scss的使用方案
react中使用scss
npm add node-sassnpm:dart-sass5.CSS in JS
安装第三方库styled-components
npm i styled-components1ES6模板字符串调用函数
我们先补充一个知识就是模板字符串竟然也能tmd调用函数参数的构成是字符串先构成一个数组作为第一个参数然后后面的参数是引用的name和age的值
function fun(...arg) {console.log(arg);
}
let name zzy;
let age 18;
fun我叫${name}我今年${age}岁;2使用styled-components的步骤
为了方便演示我们定义一个组件写上类名
export class App extends PureComponent {render() {return (divh1 classNamenav导航栏/h1div classNameboxh2 classNametitle标题/h2p classNamecontent内容内容/p/div/div)}
}定义一个style.js文件里面写
import styled from styled-components;const NiuBi styled.div.nav {color: red;}.box {border: 1px solid black;.title {font-size: 40px;:hover {background-color: blue;}}.content {color: skyblue;}}
export default NiuBi;是的你没看错这样就借助这个styled-components的库创建了一个作为div并带着样式的NiuBi组件。
紧接着我们引入NiuBi让他作为根节点包住元素这样的话NiuBi里面的所有样式我们都可以在style.js中去写而且不会和其他地方有冲突。
import NiuBi from ./style;export class App extends PureComponent {render() {return (NiuBih1 classNamenav导航栏/h1div classNameboxh2 classNametitle标题/h2p classNamecontent内容内容/p/div/NiuBi)}
}补充为了写css方便可以安装vscode的一个插件 3模板字符串props接收数据
还有一个没见过的操作css里因为用的是模板字符串我们可以通过${}去读取变量由于我们这个库返回的这个NiuBi是一个组件那么我们可以通过组件标签给它传一些数据读取的方式就是一个立即调用的箭头函数props props.color 4attrs设置属性默认值
写法如下参数是一个回调回调的参数是props。可以给一些属性设置默认值如果传了就用传的值如果没传就用默认值。
5styled-components高级特性
1、支持样式的继承 2、可以设置主题然后下面的地方如果用到styled-components包裹就可以通过props.theme去读取主题的样式 6.React中动态添加class 那么在React中怎么办呢我们可以 但是这样也比较繁琐所以我们可以借助一个第三方库classnames
1、安装
npm install classnames2、导入
import classNames from classnames;3、使用
h2 className{classNames(title,{active:true})}标题/h2更多使用方式 官方文档连接https://github.com/JedWatson/classnames