In the background management system, we often encounter the following business scenarios:
The top is search, the bottom is paginated table. The Ant Design component library has nicely wrapped the table component and the paging component together. We just need to change the column, dataSource, and other properties to implement different pages. As you write more pages, you will find that there is still some repetitive logic, that is, the logic of requesting data: when the page number is changed, you need to request data again; The logic that requests data is triggered when the query condition is modified. With this in mind, we extracted the logic and encapsulated a table group containing the request data with the ant Design component. Effect:
Initialize the
npx create-react-app page-table
npm install antd -D
Copy the code
Create-react-app initializes the project and installs the ANTD component library.
The fetch and XMLHttpRequest
In fact, we can use umi-Request and Axios to send requests. This paper USES the native fetch requests (as long as it is in order to study 😄), recommend nguyen piece “fetch API tutorial” blog (www.ruanyifeng.com/blog/2020/1)… And MDN documentation (developer.mozilla.org/zh-CN/docs/…) .
Here are a few summaries I used:
- Fetch will return one
Promise
Object. Even if the back end returns 404 or 500, no error is reported, it just returnsPromise
Object marked asresolved
And sets the OK property of the return value of resolve to false. It is marked reject only when the network fails or the request is blocked.
-
When across domains, neither FETCH nor XHR will automatically bring cookies. The FETCH request requires setting the credentials: ‘include’. XMLHttpRequest requests require the following Settings: xhr.withCredentials = true;
-
AbortController can cancel the fetch request. The XMLHttpRequest request is canceled through xhr.abort().
-
AbortController Cancelling the FETCH request results in a REJECT Promise state returned by the FETCH.
See the following code for details:
const url = "http://localhost:8081/pageTable/v1/famousInfo2? current=1&pageSize=8"
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
console.log(xhr, '-- respone')}// Request a Cookie
xhr.withCredentials = true;
xhr.open('GET', url, true);
xhr.send();
// Cancel the request
setTimeout(() = > {
xhr.abort();
}, 1500);
const controller = new AbortController();
const signal = controller.signal;
fetch(url, {
method: 'GET'.mode: 'cors'.credentials: 'include'.signal: signal
}).then(res= > {
console.log(res);
});
setTimeout(() = > {
controller.abort();
}, 1500)
Copy the code
More detailed XMLHttpRequest request: segmentfault.com/a/119000000…
The node interface
Exress is used to write a Restful query interface. Set up the cross-domain code 👇 :
// Set cross-domain access
app.all("*".function (request, response, next) {
* indicates that any domain name is allowed to cross domains. http://localhost:3000 indicates the Origin address of the front-end request
response.header("Access-Control-Allow-Origin"."http://localhost:3000");
// Set what attributes can be added to the request header
response.header('Access-Control-Allow-Headers'.'Content-Type, Content-Length, Authorization, Accept, X-Requested-With');
// Set Cookie information to be carried across domains
response.header('Access-Control-Allow-Credentials'."true");
// Sets which methods in the request header are valid
response.header(
"Access-Control-Allow-Methods"."PUT,POST,GET,DELETE,OPTIONS"
);
response.header("Content-Type"."application/json; charset=utf-8");
next();
});
Copy the code
page-table
API
Without further ado, here is the API for using the wrapped form component (which comes with request data) :
attribute | instructions | type | The default value |
---|---|---|---|
url | mandatory. The URL for the requested data | String | |
columns | mandatory. Configuration description of table columns | Array | [] |
pageInfo | Optional. The paging parameter object for the request | Object | {current: 1,pageSize: 8} |
params | Optional. The parameter object of the request | Object | {} |
isPagination | Optional. Do I need paging | Boolean | true |
type | Optional. The first column shows the check or radio, optional values have the checkbox | radio. Nothing will show if you don’t fill it in. | String | |
rowKey | Optional. Table row key value; By default, the ROW_ID field is added to the table data as the key for the row data. | String | “ROW_ID” |
A comparative event API: onSelectChange; If the first column is a checkbox | radio clicked the callback function.
const onSelectChange = (selectedRowKeys, selectedRows) = >{
console.log(selectedRowKeys, selectedRows);
}
Copy the code
The selectedRowKeys argument means that the rowKeys array is clicked on the selected row; SelectedRows represents clicking on the Rows array of selected data rows.
Send data request
It is not difficult to think of using the useEffect hook function to send a request when the page loads and to cancel the request being sent when the page unloads. Here are three very clever points:
-
🍓 useEffect (() = > {the fetch ()}, [url, params, pageOpitons]); Subtly add the dependent variable to the second parameter. Where URL and params are parameters passed in from the external parent component, that is, when the URL of the parent component or the query parameter params is modified, the Page-table component will be triggered to request background data again. PageOpitons are state data held by the Page-Table component, that is, the Page-Table component can switch pages to trigger the re-request of background data.
-
🍒 For pagination of the page-table component, the parent component can also modify pageInfo to trigger pagination modification. React Hook changes the parent props to trigger state changes of the child components. How do you solve it? Take a look at the following code 👇 :
// Initialize pageOpitons in useState
const [pageOpitons, setPageOptions] = useState({
current: pageInfo && pageInfo.current ? pageInfo.current : 1.pageSize: pageInfo && pageInfo.pageSize ? pageInfo.pageSize : 8
});
useEffect(() = >{
// When pageInfo changes and has a value, check whether it is the same as pageOpitons.
// Avoid repeated requests caused by repeated assignments.
// isEqual checks whether the key and value of pageInfo and pageOpitons are the same; Same means same.
if(pageInfo && ! isEqual(pageInfo, pageOpitons)){ setPageOptions({current: pageInfo.current,
pageSize: pageInfo.pageSize
})
}
}, [pageInfo]);
Copy the code
// common.js
function isObject(obj) {
return typeof obj === 'object'&& obj ! = =null;
}
// Check whether obj1 and obj2 are identical: key and value are identical
export function isEqual(obj1, obj2) {
if(! isObject(obj1) && ! isObject(obj1)) {// Value type comparison
return obj1 === obj2;
}
if (obj1 === obj2) {
return true;
}
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if(keys1.length ! == keys2.length) {return false;
}
for (let key of keys1) {
const res = isEqual(obj1[key], obj2[key]);
if(! res) {returnres; }}return true;
}
Copy the code
- Cancel sending requests while switching 🍍 pages. This time, mentioned above
AbortController
It works. usinguseEffect(()=>{ return ()=>{ abort();}}, []);
simulationcomponentWillUnmount
And pay attention to the use of ❗️useRef
To retainAbortController
Object, so that the cancellation is the same.
const abortControllerRef = useRef(new AbortController());
// Cancel the request
useEffect(() = > {
return () = > abortControllerRef.current.abort()
}, []);
Copy the code
The source address
Git: github.com/YY88Xu/page… Welcome to fork your valuable suggestions ❤️.