Как указано в документации React, нет гарантии того, что setState
запущен синхронно, поэтому ваш console.log
может вернуть состояние до его обновления.
Майкл Паркер упоминает о передаче обратного вызова внутри setState
. Другой способ обработки логики после изменения состояния осуществляется с помощью метода жизненного цикла componentDidUpdate
, который является методом, рекомендованным в документах React.
Обычно мы рекомендуем использовать для этой логики componentDidUpdate ().
blockquote>Это особенно полезно, когда могут быть последовательные
setState
s, и вы хотели бы запустить ту же функцию после каждого изменения состояния. Вместо добавления обратного вызова к каждомуsetState
, вы можете поместить функцию внутриcomponentDidUpdate
с конкретной логикой внутри, если необходимо.// example componentDidUpdate(prevProps, prevState) { if (this.state.value > prevState.value) { this.foo(); } }
Я думаю, что необходимо будет использовать некоторый p/invoke:
[DllImport("User32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
Видят эта статья о том, как настроить монитор буфера обмена в c#
В основном, Вы регистрируете свое приложение как программу просмотра буфера обмена с помощью
_ClipboardViewerNext = SetClipboardViewer(this.Handle);
, и затем Вы получите эти WM_DRAWCLIPBOARD
сообщение, которое можно обработать путем переопределения WndProc
:
protected override void WndProc(ref Message m)
{
switch ((Win32.Msgs)m.Msg)
{
case Win32.Msgs.WM_DRAWCLIPBOARD:
// Handle clipboard changed
break;
// ...
}
}
(существует больше, чтобы быть сделанным; передающие вещи вдоль цепочки буфера обмена и нерегистрации Вашего представления, но можно получить это от статья )
Для полноты, вот элемент управления, который я использование в производственном коде. Просто перетащите из дизайнера и дважды щелкните, чтобы создать обработчик событий. Подпроцесс
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Drawing;
namespace ClipboardAssist {
// Must inherit Control, not Component, in order to have Handle
[DefaultEvent("ClipboardChanged")]
public partial class ClipboardMonitor : Control
{
IntPtr nextClipboardViewer;
public ClipboardMonitor()
{
this.BackColor = Color.Red;
this.Visible = false;
nextClipboardViewer = (IntPtr)SetClipboardViewer((int)this.Handle);
}
/// <summary>
/// Clipboard contents changed.
/// </summary>
public event EventHandler<ClipboardChangedEventArgs> ClipboardChanged;
protected override void Dispose(bool disposing)
{
ChangeClipboardChain(this.Handle, nextClipboardViewer);
}
[DllImport("User32.dll")]
protected static extern int SetClipboardViewer(int hWndNewViewer);
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
protected override void WndProc(ref System.Windows.Forms.Message m)
{
// defined in winuser.h
const int WM_DRAWCLIPBOARD = 0x308;
const int WM_CHANGECBCHAIN = 0x030D;
switch (m.Msg)
{
case WM_DRAWCLIPBOARD:
OnClipboardChanged();
SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
break;
case WM_CHANGECBCHAIN:
if (m.WParam == nextClipboardViewer)
nextClipboardViewer = m.LParam;
else
SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
break;
default:
base.WndProc(ref m);
break;
}
}
void OnClipboardChanged()
{
try
{
IDataObject iData = Clipboard.GetDataObject();
if (ClipboardChanged != null)
{
ClipboardChanged(this, new ClipboardChangedEventArgs(iData));
}
}
catch (Exception e)
{
// Swallow or pop-up, not sure
// Trace.Write(e.ToString());
MessageBox.Show(e.ToString());
}
}
}
public class ClipboardChangedEventArgs : EventArgs
{
public readonly IDataObject DataObject;
public ClipboardChangedEventArgs(IDataObject dataObject)
{
DataObject = dataObject;
}
}
}