const LIMIT = 10;
const getProducts = async (offset, limit) => { ... }
function App () {
const [offset, setOffset] = useState(0);
const [products, setProducts] = useState([])
useEffect(() => {
getProducts(offset, LIMIT).then(products => setProducts(v => [...v, ...products]))
}, [offset]);
return <RenderProducts onScroll={() => { // increment offset }} />
}
// store.ts
const LIMIT = 30;
export const $products = map({
offset: 0,
products: [],
isLoading: true
})
onMount($products, () => {
fetchProducts()
})
const fetchProducts = action($products, "fetchProducts", async store => {
const { products, offset } = store.get();
// TODO: add error handling
store.setKey("isLoading", true);
const newPartOfProducts = await api.getProducts(offset, LIMIT);
store.setKey("products", [...products, ...newPartOfProducts ]);
store.setKey("isLoading", false);
});
const incrementOffset = action($products, "incrementOffset", store => {
const { offset } = store.get();
store.setKey("offset", offset + LIMIT);
fetchProducts()
})
export const $productsMutations = { incrementOffset }
// App.tsx
function App () {
const { isLoading, products } = useStore($products)
return (
<Fragment>
<RenderProducts onScroll={$productsMutations.incrementOffset} products={products} />
{isLoading && <LoadingIndicator />}
</Fragment>
)
}
const ref = useRef<HTMLDivElement>(null);
const prevRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (ref.current === prevRef.current) { return; }
prevRef.current = ref.current;
// реф поменялся, что-то делаем
});
const root = ReactDOM.createRoot(document.getElementById('root'));
const container = ReactDOM.createContainer(document.getElementById('root'), false, false);
ReactDOM.updateContainer(element, container, null, () => {
// Callback, который вызывается после завершения обновления
});
const fiberRoot = ReactDOM.createFiberRoot(container, false);
server {
listen 80 default_server;
listen [::]:80 default_server;
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
ssl_certificate /etc/letsencrypt/live/site.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/site.com/privkey.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
ssl_session_tickets off;
# curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam
# ssl_dhparam /path/to/dhparam;
# intermediate configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
# HSTS (ngx_http_headers_module is required) (63072000 seconds)
add_header Strict-Transport-Security "max-age=63072000" always;
ssl_stapling on;
ssl_stapling_verify on;
location / {
root /var/www/html/;
autoindex off;
if ( $request_uri ~ "/index.html" ) {
rewrite ^(|/(.*))/index\.html$ /$2 permanent;
}
}
}
if (__DEV__) {
console.warn('Some warning message');
}
type Posts = Post[]
const result = blogPosts[props.name as keyof typeof blogPosts]
const result = (blogPosts as Posts)[props.name]
blogPosts
- нужного типа:// тайпргард: тут проверка что posts действительно Posts;
const isPosts = (posts: unknown): posts is Posts => !!posts
&& typeof posts === 'object'
//&& ... ;
if (!isPosts(blogPosts)) throw new Error('wrong blogPosts');
const result = blogPosts[props.name];
app/blog
- можешь создать layout.tsx, а все вложенные папки это и будут children которые попадают в этот layout.tsx - типа вложенных страниц, но на самом деле не так, layout.tsx - это просто обёрткаconst BlogLayout = ({ children }) => {
return (
<section>
<SomeComponent/>
{children}
</section>
)
};
export default BlogLayout ;
&
) как верно подметил Василий Банников )interface A extends B, C {}
interface B {}
type C = {}; // interface вполне может extends из type
interface A {
a: number;
}
interface A {
b: number;
}
const a: A = {a: 1, b: 2};
type A = B | C; // на interface такого не выразишь