uncontrolled components
function Uncontrolled(){
const testRef = useRef(null)
const handleClick = ()=>{
console.log(testRef.current.value)
}
return(
<input onClick={handleClick} ref = {testRef}></input>
)
}
What is the difference between createElement and cloneElement
let div1 = React.createElement('div',{name:'div1'},'hello word')
//cloneElement
const Form = ({ children }) => {
return React.Children.map(children, child =>
React.cloneElement(child, { onChange: () => console.log('Form Change!') })
);
};
const App = () => (
<Form>
<input type="text" />
<input type="password" />
</Form>
);
export default App;
Errors
"Cannot use import statement outside a module"
- typically occurs when you're trying to use ES6 import and export syntax in an environment that doesn't support ES6 modules.
- Make sure your JavaScript file is treated as an ES6 module. You can do this by adding the "type": "module" field in your package.json file.
Lifting State Up
if two child components share the same data from its parent, then move the state to parent
A higher-order component (HOC)
an easy example for HOC
import React from "react";
const Parent = (Child) => {
//HOC 的参数是组件,返回值是一个组件,组件的返回值的jsx,所以需要两个return
return (props) => {
const styleObj = {
backgroundColor: 'red'
}
//返回jsx
return (
<Child index = '1' ></Child>
)
}
}
const Child = (props) => {
return (
<div index = {props.index} className="child">this is a child component</div>
)
}
const Family = Parent(Child)
const HOC = () => {
return (
<Family />
)
}
export default HOC
使用HOC鉴权的例子
/*
利用HOC,实现鉴权,如果用户未登陆则跳转到登陆页
*/
import React from "react";
//鉴权的高阶函数
const Authentic = (Child) => {
return (props) => {
const isAuth = checkIfAuth()
if (isAuth) {
return (
<Child />
)
}
else {
return (
<Login />
)
}
}
}
//登陆后才可以看到的组件
const protectedComponent = (props) => {
return (
<div>protected component</div>
)
}
//包装后的组件
const Destination = Authentic(protectedComponent)
const AuthenticHOC = () => {
return (
<Destination />
)
}
export default AuthenticHOC
Children Prop
/*
children props 的用法
*/
import React from "react";
export default function ChildrenProps() {
// pass components as data to other components
const Form = ({ children }) => {
return (
<div className="form">
{
//map的回调函数里面要用return 返回需要渲染的组件,不改变原数组
React.Children.map(children, (item, index) => {
//使用cloneElement创建新的标签,不修改原来的标签
return React.cloneElement(item, { className: `div+${index}` })
})
}
{
//forEach对数组的每个元素执行副作用函数,可能改变原数组,无返回值
React.Children.forEach(children,element => {
console.log(element,'forEach')
})
}
{
//用来数有多少个孩子节点
React.Children.count(children)
}
{
//确保值接受一个孩子节点,多个会报错
React.Children.only(children)
}
</div>
)
}
return (
<Form>
<div>children props 1</div>
</Form>
)
}
map和forEach的区别
Reconciliation
- Reconciliation is the process through which React updates the Browser DOM and makes React work faster.
- React use a diffing algorithm so that component updates are predictable and faster.
- React would first calculate the difference between the real DOM and the copy of DOM (Virtual DOM) when there's an update of components.
- React stores a copy of Browser DOM which is called Virtual DOM.
- When we make changes or add data, React creates a new Virtual DOM and compares it with the previous one. This comparison is done by Diffing Algorithm.
- Now React compares the Virtual DOM with Real DOM. It finds out the changed nodes and updates only the changed nodes in Real DOM leaving the rest nodes as it is. This process is called Reconciliation.
lazy function
//懒导入模块,使用React.lazy(在回调函数中导入模块)
const LazyComponent = React.lazy(() => import('./test/LazyComponent'))
//使用的时候用React.suspense包裹住
<React.Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</React.Suspense>
- When you use a default export, the import statement can directly reference the component without destructuring, which aligns with how React.lazy expects the module to be structured.
- If you would like to import modules which are named exports, you can create an intermediate module that reexports it as the default.
// MoreComponents.js
export const SomeComponent = /* ... */;
export const UnusedComponent = /* ... */;
// IntermediateComponent.js
export { SomeComponent as default } from "./MoreComponents.js";
import React, { lazy } from "react";
const SomeComponent = lazy(() => import("./IntermediateComponent.js"));
Why React uses className over class attribute?
- The attribute names written in JSX turned into keys of JavaScript objects and the JavaScript names cannot contain dashes or reversed words.
- it is recommended to use camelCase wherever applicable in JSX code.
- The attribute class is a keyword in JavaScript, and JSX is an extension of JavaScript.
- That's the principle reason why React uses className instead of class. Pass a string as the className prop.
What are portals in React?
- while your React component is part of a particular hierarchy in the React tree, using a portal allows you to render its output elsewhere in the actual DOM structure.
Why use Portals
- certain UI elements require rendering outside of their parent container's DOM tree
- Rendering Components at a higher level in the DOM ensures they aren't constrained by parent elements' overflow: hidden or z-index properties.
- rendered at a top-level DOM node to ensure consistent positioning and behavior across the application.
Createing a Protal
import { createPortal } from "react-dom";
import React from "react";
//要从react-dom包里面引入createProtal方法
export default function CreatePortalTest() {
return (
<>
{
createPortal(
<div>createPortal test</div>, document.body
)
}
</>
)
}
Rendering React components into non-React server markup
- use a portal to manage the content of a DOM node that’s managed outside of React.
import { useRef, useEffect, useState } from 'react';
import { createPortal } from 'react-dom';
import { createMapWidget, addPopupToMapWidget } from './leafLetMap';
export default function Map() {
const containerRef = useRef(null);
const mapRef = useRef(null);
const [popupContainer, setPopupContainer] = useState(null);
useEffect(() => {
if (mapRef.current === null) {
const map = createMapWidget(containerRef.current);
//使用ref和使用getElementById的结果是一样的,但是ref更快
console.log(document.getElementById('mapID'),containerRef.current)
mapRef.current = map;
const popupDiv = addPopupToMapWidget(map);
setPopupContainer(popupDiv);
}
}, []);
return (
<div id = "mapID" style={{ width: 250, height: 250 }} ref={containerRef}>
{popupContainer !== null && createPortal(
<p>Hello from React!</p>,
popupContainer
)}
</div>
);
}
What are stateless components?
- React components that do not manage their own state. They receive data and props from parent components and render UI based on that.
//用作展示组件
import React from 'react';
const Greeting = ({ name }) => {
return <h1>Hello, {name}!</h1>;
};
// Usage
const App = () => {
return <Greeting name="Alice" />;
};
export default App;
How to apply validation on props in React?
- using the prop-types library.
import React from "react";
import PropTypes from 'prop-types'
const PropTypeTest = (props) => {
return (
<div>{props.name}</div>
)
}
//给组件添加类型检测
PropTypeTest.propTypes = {
//如果name不是true,会报错。
name: PropTypes.string.isRequired
}
export default function PropTypesIndex() {
return (
<PropTypeTest name='name' />
)
}
What are the limitations of React?
- React is just a view library, not a full framework.